- 论坛徽章:
- 0
|
经过两天的折腾,总结一下:
1:pthread_mutex_lock(&_mutex); 这个函数调用因为使用了全局变量_mutex所以是不可重入的,在信号处理函数中再次调用pthread_mutex_lock(&_mutex)时就会出现问题,具体内部我猜想是这样的:如果说pthread_mutex_lock函数执行完毕了,然后收到信号并处理的话这样不会出现问题,因为锁是递归锁;现在pthread_mutex_lock函数没有执行完毕的时候收到信号并处理(见pstack的结果),此时的某些内部数据可能有一半处理好了,一半没有处理好,在信号处理函数中再次调用pthread_mutex_lock时可能就检查到死锁了,这时可能认为这个锁不是递归锁,因为内部数据不完整了,判断就有可能发生错误。如果在单独的线程中处理信号则不会出现死锁,这是因为这里的死锁是因为多次锁造成的,不同线程锁同一个锁时不会产生死锁,只会等待;
2:虽然pthread_mutex_lock使用了全局变量,但事实上他是线程安全的,因为不是所有的使用全局变量的函数都不是线程安全,pthread_mutex_lock函数本身在线程安全方面会做保证。
3:在freebsd下面不会发生死锁,说明freebsd这块儿的实现比linux要好一些;
4:在主函数中调用pthread_mutex_lock和pthread_mutex_unlock时阻塞信号也不会产生死锁,这证明了上面的猜想。另外如果在pthread_mutex_lock和pthread_mutex_unlock中间有printf函数的话还是会出现死锁,这应该是因为printf调用了puts,puts本身用到锁了。
带信号阻塞的代码如下:- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <signal.h>
- #include <string.h>
- #include <errno.h>
- pthread_mutex_t _mutex;
- pthread_mutexattr_t _attr;
- void prompt_info(int signo)
- {
- pthread_mutex_lock(&_mutex);
- printf("in signal\n");
- pthread_mutex_unlock(&_mutex);
- }
- // 建立信号处理机制
- void init_sigaction(void)
- {
- struct sigaction tact;
-
- /*信号到了要执行的任务处理函数为prompt_info*/
- tact.sa_handler = prompt_info;
- tact.sa_flags = SA_RESTART|SA_NODEFER;
- tact.sa_flags = 0;
- /*初始化信号集*/
- sigemptyset(&tact.sa_mask);
- /*建立信号处理机制*/
- sigaction(SIGALRM, &tact, NULL);
- }
- void init_time()
- {
- struct itimerval value;
-
- /*设定执行任务的时间间隔*/
- value.it_value.tv_sec = 0;
- value.it_value.tv_usec = 1;
- /*设定初始时间计数*/
- value.it_interval = value.it_value;
- /*设置计时器ITIMER_REAL*/
- setitimer(ITIMER_REAL, &value, NULL);
- }
- int main()
- {
- pthread_mutexattr_init(&_attr);
- pthread_mutexattr_settype(&_attr,PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&_mutex, &_attr);
- init_sigaction();
- init_time();
- int ret;
- sigset_t bset,oset;
- sigemptyset(&bset);
- sigaddset(&bset, SIGALRM);
- while ( 1 ) {
- pthread_sigmask(SIG_SETMASK, &bset, &oset);
- ret = pthread_mutex_lock(&_mutex);
- pthread_sigmask(SIG_SETMASK, &oset, NULL);
- if(0!= ret) {
- printf("lock error in main is %d\n",errno);
- perror("error info is ");
- }else {
- //printf("in main\n");
- pthread_sigmask(SIG_SETMASK, &bset, &oset);
- pthread_mutex_unlock(&_mutex);
- pthread_sigmask(SIG_SETMASK, &oset, NULL);
- }
- }
- return 0;
- }
复制代码 |
|