线程安全

来源:互联网 发布:天佑鲍比知乎 编辑:程序博客网 时间:2024/06/09 15:52

假设一种情况,编写mysleep()函数。

#include <stdio.h>#include <unistd.h>#include <signal.h>void myhandler(int sig){    printf("%d signal\n", sig);}int mysleep(int timeout){    struct sigaction act, oact;    act.sa_handler = myhandler;    act.sa_flags = 0;    sigemptyset(&act.sa_mask);    sigaction(SIGALRM, &act, &oact);    alarm(timeout);    pause();    int ret = alarm(0);    sigaction(SIGALRM, &oact, NULL);    return ret;}int main(){    while(1)    {        mysleep(2);        printf("mysleep 2s\n");    }}

这里写图片描述
但如果在定时器刚设定好时,
系统却执行高优先级的进程去了,并且需要较长时间,
此时定时器已经设置,但是进程却没有被挂起,
此时定时器可能已经到达时间了,内核发送SIGALRM信号给该进程,但进程处于未决状态,
等到高优先级进程执行完毕,系统开始执行该进程的下一句pause(),
进程被挂起,一直在等待,此时已经没有定时器来唤醒进程,就会导致进程结果出现异常。
这是因为进程时序的问题而导致的进程结果出现异常,也被称为竟态条件。
那么如何解决这个问题呢?
1.屏蔽SIGALRM信号
2.alarm(n s)//设置定时器
3.解除屏蔽
4.pause()
但是在解除屏蔽和挂起信号之间,SIGALRM仍有可能递达,那么只要将解除屏蔽和递达一起执行就可以了,将它们合成一个原子操作,sigsuspend()包含了pause()的挂起等到功能。

#include <stdio.h>#include <unistd.h>#include <signal.h>void myhandler(int sig){    printf("%d signal\n", sig);}int mysleep(int timeout){    struct sigaction act, oact;    sigset_t nmask, omask, smask;    act.sa_handler = myhandler;    sigemptyset(&act.sa_mask);    act.sa_flags = 0;    sigaction(SIGALRM, &act, &oact);    sigemptyset(&nmask);    sigaddset(&nmask, SIGALRM);    sigprocmask(SIG_BLOCK, &nmask, &omask);    alarm(timeout);    smask = omask;    sigdelset(&smask, SIGALRM);    sigsuspend(&smask);    int ret = alarm(0);    sigaction(SIGALRM, &oact, NULL);    sigprocmask(SIG_SETMASK, &omask, NULL);    return ret;}int main(){    while(1)    {        mysleep(2);        printf("mysleep 2s\n");    }}
原创粉丝点击