Linux信号透彻分析理解与各种实例讲解( 八 )

第一次发送sigqueue时 , 由于主函数持有锁 , 因此 , sem_trywait返回-1 , 当第二次发送sigqueue时 , 主函数已经释放锁 , 此时就可以在信号处理函数中对临界资源加锁了 。
但这种方法明显丢失了一个信号 , 不是很好的解决方法 。
3. 利用双线程来解决主函数与信号处理函数死锁
我们知道 , 当进程收到一个信号时 , 会选择其中的某个线程进行处理 , 前提是这个线程没有屏蔽此信号 。 因此 , 可以在主线程中屏蔽信号 , 另选一个线程去处理这个信号 。 由于主线程与另外一个线程是平行执行的 , 因此 , 等待主线程执行完临界区时 , 释放锁 , 这个线程去执行信号处理函数 , 直到执行完毕释放临界资源 。
这里用到一个线程的信号处理函数: pthread_sigmask
int pthread_sigmask(int how,const sigset_t *set,sigset_t *oldset);
这个函数与sigprocmask很相似 。
how:
SIG_BLOCK 将信号集加入到线程的阻塞集中去
SIG_UNBLOCK 将信号集从阻塞集中删除
SIG_SETMASK 将当前集合设置为线程的阻塞集
示例: 利用双线程来解决主函数与信号处理函数之间的死锁
#include#include#include#include#include#include#includevoid*thread_function(void *arg);//线程处理函数void myhandler(int signo,siginfo_t *si,void *vcontext);//信号处理函数int value;sem_t semlock;int main(){int res;pthread_t mythread;void *thread_result;res=pthread_create(//创建一个子线程if(res!=0){perror("线程创建失败");}//在主线程中将信号屏蔽sigset_t empty;sigemptyset(sigaddset(pthread_sigmask(SIG_BLOCK,//主线程中对临界资源的访问if(sem_init(}sem_wait(printf("主线程已经执行/n");value=http://kandian.youth.cn/index/1;sleep(10);sem_post(res=pthread_join(mythread,//等待子线程退出exit(EXIT_SUCCESS);}void *thread_function(void *arg){struct sigaction oldact,newact;newact.sa_sigaction=myhandler;newact.sa_flags=SA_SIGINFO;//注册信号处理函数sigaction(SIGUSR1,union sigval val;val.sival_int=1;printf("子线程睡眠3秒/n");sleep(3);sigqueue(getpid(),SIGUSR1,val);pthread_exit(0);//线程结束}void myhandler(int signo,siginfo_t *si,void *vcontext){sem_wait(value=http://kandian.youth.cn/index/0;printf("信号处理完毕/n");sem_post(}运行结果如下:主线程已经执行子线程睡眠3秒信号处理完
解释一下:
在主线线程中阻塞了SIGUSR1信号,首先让子线程睡眠3秒 , 目的让主线程先运行 , 然后当主线程访问临界资源时 , 让线程sleep(10),在这期间 , 子线程发送信号 , 此时子线程会去处理信号 , 而主线程依旧平行的运行 , 子线程被阻止信号处理函数的sem_wait处 , 等待主线程10后 , 信号处理函数得到锁 , 然后进行临界资源的访问 。 这就解决了主函数与信号处理函数之间的死锁问题 。
扩展: 如果有多个信号到达时 , 还可以用多线程来处理多个信号 , 从而达到并行的目的 , 这个很好实现的 , 可以尝试一下 。


推荐阅读