线程安全与可重入函数

来源:互联网 发布:外国法制史 知乎 编辑:程序博客网 时间:2024/06/05 09:10

线程安全

一个函数称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。
线程安全问题主要是由全局变量和静态变量引起的。
如果每个线程对全局变量,静态变量只有读操作,没有写操作。一般来说这个全局变量是线程安全的。当多个线程同时执行写操作,要保证线程安全,一般就要保证线程的同步问题。
因为全局变量引起的线程安全

#include<stdio.h>#include<pthread.h>int num=0;void* fun(){    int i=0;    while(i<1000)    {        int temp=num;        printf("thread is:%u,g_val:%d\n",pthread_self(),num);        num=temp+1;        i++;    }}int main(){    pthread_t id1,id2;    pthread_create(&id1,NULL,fun,NULL);    pthread_create(&id2,NULL,fun,NULL);    pthread_join(id1,NULL);    pthread_join(id2,NULL);    printf("%d\n",num);    return 0;}

这里写图片描述
这里的结果并不是1000,而且多次运行结果也不一样。两个线程对于一个全局变量的操作不是原子的,两个线程操作同一块代码顺序是不可预期的。

可重入函数

可重入函数是线程安全的一类。函数被不同的控制流程调用时,有可能在第一次调用时还没返回时就再次进入该函数,称为重入。
一个程序main函数调用insert函数向一个链表中插入一个节点,插入需要两步,新节点temp,当前节点cur,temp->next=cur和head=temp两步操作。当只进行了第一步时,因为硬件中断使得进程切换到内核态,再次回到用户态时检测到有信号要处理,于是执行了这个信号,也是调用insert函数插入节点,插入成功后返回到内核态,再次返回到用户态就继续往下执行,刚开始做了一步的插入操作就被打断。最后插入了两个节点,却只有一个节点真正的插入进去了。像这种函数称为不可重入函数,insert访问的是一个全局链表,因为重入而错乱。反之,一个函数之访问自己的局部变量或参数,称为可重入函数

两者比较

1.线程安全是在多线程的情况下引发的,可重入函数时一个线程
2.线程安全不一定是可重入的,但可重入一定是线程安全的
3.如果一个函数由全局变量,这个函数的线程不是线程安全也不是可重入的。
4.如果一个函数当中的数据有自身的栈空间,则这个函数是线程安全且是可重入函数。
5.如果对临界资源的访问加锁,则这个函数是线程安全的。但如果这个重入函数锁未释放就会产生死锁,则是不可重入的。
6.线程安全能够使不同的线程访问同一块地址空间,可重入要求不同的执行流对数据的操作互不影响的结果相同。

原创粉丝点击