您的位置:首页 > 其它

多线程下安全的信号处理

2009-11-08 14:20 267 查看
最近项目上出现了一个小问题,今天把这个问题修补了一下。为此在博客上也做个记录。

问题是有关端口绑定引起的,原来我们在做测试的时候,一般用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: