天天看點

sigsetjmp siglongjmp使用時要注意記憶體洩露

如果你在sigsetjmp條件内構造了一個對象,那麼很容易造成記憶體洩露,程式的

突然跳轉,導緻析構函數還沒有執行.以下是測試代碼

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>
#include <signal.h>
#include <time.h>
#include <assert.h>
#include <errno.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <pthread.h>
class A{

public:
A(){
i=0;
printf("constructor\n");
}
~A(){
printf("unconstructor\n");
}
int i;
};
pthread_t tid_result_manager;
jmp_buf jb_result_manager;
void sigexit_main(int)
{
	printf("主線程接收到了退出信号。\n" );
	pthread_kill( tid_result_manager,SIGUSR1 );
	return;
}
void sigalrm(int s) { 
	printf("sigalrm signal=%d\n",s);
    siglongjmp( jb_result_manager, 1 );   //此處傳回1 ,繼續執行
}
void sigexit(int s) {
	printf("sigexit signal=%d\n",s);
	pthread_t tid = pthread_self();
	if ( tid == tid_result_manager )
        siglongjmp( jb_result_manager, -1 );  //傳回-1
	assert(0);
}
int icout=0;
void *result_manager( void * )
{
	sigset_t set;
    int alarm_time = 2;
int ret=0;

	printf("線程啟動。\n" );

    signal( SIGUSR1, sigexit );

    signal( SIGALRM, sigalrm );
	sigemptyset( &set );
	sigaddset( &set, SIGUSR1 );
    sigaddset( &set, SIGALRM );
    pthread_sigmask( SIG_UNBLOCK, &set, NULL );  //不阻止SIGUSR1信号


    if ( ( ret = sigsetjmp( jb_result_manager, 1 ) ) != -1 ) {
        if ( ret ) {
				printf("ret=%d,alarm_time=%d\n",ret,alarm_time);
				pthread_sigmask( SIG_BLOCK, &set, NULL );

			
icout++;
	if(icout<5)
{
alarm( alarm_time ); 

}
			A a;
			a.i++;
printf("cccc a.i=%d\n",a.i);
			sleep(5);
				alarm(0);  //取消定時器
				printf("線程内 ,取消 定時器之後 \n");
				pthread_sigmask( SIG_UNBLOCK, &set, NULL );
			  // while ( 1 ) pause(); //讓程式等待信号
			}
printf("waiting signal。\n" );
			while ( 1 ) pause(); //讓程式等待信号
	}
	printf("線程退出。\n" );
	return NULL;
}
int main( int argc, char *argv[] )
{

   printf("pid=%d",getpid());
	sigset_t set;
	sigfillset( &set );
	sigprocmask( SIG_BLOCK, &set, NULL );
   pthread_create( &tid_result_manager, NULL, result_manager, NULL ); 

	signal( SIGINT, sigexit_main );
	signal( SIGTERM, sigexit_main );
	signal( SIGQUIT, sigexit_main );
	sigemptyset( &set );
	sigaddset( &set, SIGINT );
	sigaddset( &set, SIGTERM );
	sigaddset( &set, SIGQUIT );
	pthread_sigmask( SIG_UNBLOCK, &set, NULL );
sleep(5);

  pthread_kill( tid_result_manager, SIGALRM );
printf("SIGALRM sigal sended\n");
	pthread_join( tid_result_manager, NULL );
	printf("program退出。\n" );
	return 0;
}
           

列印結果為

pid=5487線程啟動。

waiting signal。

SIGALRM sigal sended

sigalrm signal=14

ret=1,alarm_time=2

constructor

cccc a.i=1

線程内 ,取消 定時器之後

sigalrm signal=14

ret=1,alarm_time=2

constructor

cccc a.i=1

線程内 ,取消 定時器之後

sigalrm signal=14

ret=1,alarm_time=2

constructor

cccc a.i=1

線程内 ,取消 定時器之後

sigalrm signal=14

ret=1,alarm_time=2

constructor

cccc a.i=1

線程内 ,取消 定時器之後

sigalrm signal=14

ret=1,alarm_time=2

constructor

cccc a.i=1

線程内 ,取消 定時器之後

unconstructor

waiting signal。

主線程接收到了退出信号。

sigexit signal=10

線程退出。

program退出。

可以很明顯的看到析構函數就執行了最後一次,是以使用時一定要小心.盡可能少使用sigsetjmp siglongjmp函數,有個問題,為什麼線程内 ,取消 定時器之後能被列印出來?

繼續閱讀