可重入函数和线程安全的对比

来源:互联网 发布:如何描述淘宝店铺 编辑:程序博客网 时间:2024/06/03 12:27

线程安全

一般说来,一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。 

要保证线程安全,重点是保护共享资源,如全局变量、静态局部变量。为了解释线程安全,可以模拟实现一个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

当多个执行流进入这个函数时,就会出问题




0 0