Linux信号透彻分析理解与各种实例讲解( 六 )
此程序将一直阻塞在信号处理函数的sem_wait函数处 。
2. 利用测试锁解决死锁
sem_trywait(是非阻塞的sem_wait,如果加锁失败或者是超时 , 则返回-1 。
示例2: 用sem_trywait来解决死锁
#include#include#include#include#include#includeint value=http://kandian.youth.cn/index/0;sem_t sem_lock;//定义信号量void myhandler(int signo,siginfo_t *si,void *vcontext);//进程处理函数声明int main(){union sigval val;val.sival_int=1;struct sigaction oldact,newact;int res;res=sem_init(if(res!=0){perror("信号量初始化失败");}newact.sa_sigaction=myhandler;newact.sa_flags=SA_SIGINFO;sigaction(SIGUSR1,sem_wait(printf("xxxx/n");value=http://kandian.youth.cn/index/1;sleep(10);sigqueue(getpid(),SIGUSR1,val);//sigqueue发送带参数的信号sem_post(sleep(10);sigqueue(getpid(),SIGUSR1,val);exit(0);}void myhandler(int signo,siginfo_t *si,void *vcontext){if(sem_trywait(sem_post(}} 第一次发送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后 , 信号处理函数得到锁 , 然后进行临界资源的访问 。 这就解决了主函数与信号处理函数之间的死锁问题 。
扩展: 如果有多个信号到达时 , 还可以用多线程来处理多个信号 , 从而达到并行的目的 , 这个很好实现的 , 可以尝试一下 。
- 用户|5G信号有猫腻,又在考验用户的智商?
- 拍照|iPhone12还没捂热13就曝光了,屏幕、信号、拍照均有升级!
- 移植|开发者将移植ARM Mac的Linux系统 但需要得到资金支持
- 高通|为什么iphoneXR和iphoneXS信号不稳定?原因正式被确认,望周知!
- 阻挡|5G的推出真的阻挡了4G 的信号?中国移动正面给出回应
- Linux|知名开发者要把Linux移植到苹果M1 Mac上
- Linux(服务器编程):百万并发服务器系统参数调优
- linux配置nginx定时日志分割
- Linux 之父对 C++ 进行了炮轰,C++不值得推荐?
- Linux信号量(2)-POSIX 信号量
