多线程下安全的信号处理

最近项目上出现了一个小问题,今天把这个问题修补了一下。为此在博客上也做个记录。

问题是有关端口绑定引起的,原来我们在做测试的时候,一般用ctrl+c退出server程序,这样退出有一个问题。上次bind的端口仍然被占用着,如果马上重新执行server程序,那么会出现"bind listening sockey falure!"的情况,这样的话要等待一会儿,才能重新运行程序。为此我修改了一下代码,在里面添加了一个专门用来捕获SIGINT信号的线程,用这个线程来处理信号,回收资源。具体的代码如下:

v_int_32 start() { v_int_32 ret = 0; v_int_32 created_threads = 0; sigset_t bset, oset; sigemptyset(&bset); sigaddset(&bset, SIGINT);//建立一个信号集,将SIGINT添加进去 if (pthread_sigmask(SIG_BLOCK, &bset, &oset) != 0) {//设置父线程的信号掩码,子线程会继承这信号掩码 printf("set thread signal mask failrue!/n"); } ret = pthread_create(&receive_thread_, NULL, receive_packet, (void*)analysis_queue_); if (ret != 0) { //error, destroy tc list lock pthread_rwlock_destroy(&tc_list_lock); pthread_rwlock_destroy(&ip_list_lock); return ERROR_THREAD_CREATE; } usleep(INIT_TIME); for (v_int_32 j=0; j<ANALYSE_THREAD_MAX; j++) { ret = pthread_create(&analyze_thread_[j], NULL, analysis_packet, (void*)analysis_queue_[j]); if (ret != 0) { break; } created_threads++; usleep(INIT_TIME); //To ensure the binding to cpu is finished } ret = pthread_create(&signal_handle_thread_, NULL, handle_signal, NULL); if (ret != 0) { //error, destroy tc list lock pthread_rwlock_destroy(&tc_list_lock); pthread_rwlock_destroy(&ip_list_lock); return ERROR_THREAD_CREATE; } ret = pthread_create(&monitor_thread_, NULL, receive_monitor_command, NULL); if (ret != 0) { //error, destroy tc list lock pthread_rwlock_destroy(&tc_list_lock); pthread_rwlock_destroy(&ip_list_lock); return ERROR_THREAD_CREATE; } usleep(INIT_TIME); if(created_threads != ANALYSE_THREAD_MAX) { //error, destroy tc list lock pthread_rwlock_destroy(&tc_list_lock); pthread_rwlock_destroy(&ip_list_lock); return ERROR_THREAD_CREATE; } pthread_join(receive_thread_, NULL); printf("receive thread %d canceled!/n/n", receive_thread_); for (v_int_32 k=0; k<ANALYSE_THREAD_MAX; k++) { if(analyze_thread_[k] != 0) { pthread_join(analyze_thread_[k], NULL); printf("analyse thread %d canceled!/n/n", analyze_thread_[k]); } } pthread_join(monitor_thread_, NULL); printf("monitor thread %d canceled!/n/n", monitor_thread_); pthread_join(signal_handle_thread_, NULL); printf("signal thread %d canceled!/n/n", signal_handle_thread_); return NO_ERROR; }

 

上面这个是主函数,它创建了1个receive_thread_, MAX个analyse_thread_, 1个signal_handle_thread_和1个monitor_thread_,其中monitor_thread_在接受到一个连接的时候还会创建一个send_to_monitor_thread_。之所以要在父线程创建子线程之前,将SIGINT信号加入阻塞信号集,是因为子线程会继承父线程的信号掩码,即对于子线程来说,SIGINT信号也在自己的阻塞信号集之中。当阻塞信号产生的时候,如果线程对该信号的动作是默认动作或者捕获信号,那么这个阻塞信号将会被挂起,知道线程解开信号的阻塞,或者改变动作为忽略。 对于我们这个例子来说,当所有的线程接受到SIGINT信号的时候,除了signal_handle_thread_线程之外的所有线程将继续执行。signal_thread等到SIGINT信号的时候,将会取消掉其他几个子线程,并且回收资源。signal_thread_是用来捕获SIGINT信号的线程,它的工作代码如下:

void* DpiPacketProcesser::handle_signal(void*) { sigset_t waitset, oset; int sig; sigemptyset(&waitset); sigaddset(&waitset, SIGINT);//将SIGINT信号加入等待的信号集当中 sigwait(&waitset, &sig);//在此阻塞,知道SIGINT信号到达 if (send_to_monitor_thread_ != 0) {//如果有这个线程,则终止它 //cancel send thread printf("/ncancel send thread!/n"); pthread_cancel(send_to_monitor_thread_); printf("wait for send thread!/n"); pthread_join(send_to_monitor_thread_, NULL); printf("send thread %d canceled!/n/n", send_to_monitor_thread_); } //cancel receive thread printf("cancel receive thread!/n"); pthread_cancel(receive_thread_);//取消reveive_thread_ printf("wait for receive thread!/n/n"); //cancel analyse thread for (v_int_32 k=0; k<ANALYSE_THREAD_MAX; k++) { if(analyze_thread_[k] != 0) { printf("cancel the analyse thread!/n"); pthread_cancel(analyze_thread_[k]);//取消analyse_thread_ printf("wait for analyse thread!/n/n"); } } //cancel monitor thread printf("cancel monitor thread!/n"); pthread_cancel(monitor_thread_);//取消monitor_thread_ printf("wait for monitor thread!/n/n"); //close listening socket close(listen_sock);//关闭监听套接口 printf("listen socket closed!/n"); //destroy tc list lock pthread_rwlock_destroy(&tc_list_lock); printf("tc_list_lock destroyed!/n"); //destroy ip list lock pthread_rwlock_destroy(&ip_list_lock); printf("tc_list_lock destroyed!/n/n"); return NULL; }

你可能感兴趣的:(JOIN,thread,多线程,list,null,Signal)