线程安全
一般说来,一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。
要保证线程安全,重点是保护共享资源,如全局变量、静态局部变量。为了解释线程安全,可以模拟实现一个sleep函数。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void handler(int sig)//信号捕捉处理函数
{
printf("i am handler, alarm ringing\n");
}
int mysleep(int timeout)
{
struct sigaction act, oact;
act.sa_handler = handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, &oact);
alarm(timeout);
pause();
int ret = alarm(0);//闹钟置空
sigaction(SIGALRM, &oact, &act);
return ret;//ret接收了上次闹钟剩余时间,若不等于0出错
}
这个函数有一个很隐蔽的错误,假设在设定闹钟之后,当前线程被切到后台等待,而这个线程的优先级非常低,当他恢复到前台时,
闹钟设定的信号已经发送,而线程没有收到,继续执行pause,此时永远不会被唤醒。
想要解决只要分四步:
1.屏蔽信号
2.设定闹钟
3.解除屏蔽
4.pause
但是,这个方法也有危险,在3、4步之间也有可能被切出去,只能把pause换成sigsuspend来解决。
理清了思路,把代码做如下修改
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void handler(int sig)
{
printf("i am handler, alarm ringing\n");
}
int mysleep(int timeout)
{
struct sigaction act, oact;
act.sa_handler = handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, &oact);
sigset_t mask, omask, suspmask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, &omask);
alarm(timeout);
suspmask = omask;
sigdelset(&suspmask, SIGALRM);
sigsuspend(&suspmask);
int ret = alarm(0);
sigaction(SIGALRM, &oact, &act);
sigprocmask(SIG_SETMASK, &omask, NULL);
return ret;
}
可重入函数
一个函数被称作可重入的,当且仅当可以被多个执行流进入而保证不出错
可重入与线程安全并不等同。一般说来,可重入的函数一定是线程安全的,但反过来不一定成立
一个单链表插入函数分三步:创建node、node指向head指向的节点 、head指向node
当多个执行流进入这个函数时,就会出问题
940

被折叠的 条评论
为什么被折叠?



