线程安全和可重入函数

线程安全:
一个函数被称为线程安全的,当且仅当被多个进程反复调用时,它会一直产生正确的结果。
有四类函数称为线程不安全函数:
  1. 不保护共享变量的函数
  2. 函数状态随着调用改变的函数
  3. 返回指向静态变量指针的函数
  4. 调用线程不安全函数的函数

要确保函数线程安全,主要需要考虑的是线程之间的共享变量。属于同一进程的不同线程会共享进程内存空间中的全局区和堆,而私有的线程空间则主要包括栈和寄存器。因此,对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量、局部静态变量、分配于堆的变量都是共享的。在对这些共享变量进行访问时,如果要保证线程安全,则必须通过加锁的方式。

可重入函数:
函数被不同控制流程调用,有可能在第一次调用还没返回时就在次进入该函数,这称为重入。
当程序运行某一个函数时,这个函数 对一个全局变量进行处理,可能会因为中断或者异常而陷入内核,这时如果有信号去处理,而处理信号的动作会在次调用这个函数,那么当信号处理完成之后恢复中断函数的上下文信息在次执行时, 对于全局变量来说已经发生了改变,所以函数对其进行操作的结果也会发生改变,得到一个我们预期不到的结果。系统在运行时有很多不确定性,有可能会产生信号也有可能不会产信号,所以运行结果可能正确也有可能出错,这样的函数称为 不可重入函数

可重入函数只访问自己的局部变量或者参数。
一个可重入函数可以被多个执行流重复进入,内部使用的数据都应该来自于自身的栈空间包括返回值也不应该是全局或者静态的,可以允许有该函数的多个副本在运行,而正是因为其中的操作数据都来自于自身的栈空间,而每次调用函数会开辟不同的栈空间,因此二者互不影响。

不可重入函数的实例:

#include<stdio.h>
#include<stdlib.h>

int i = 0;

void add()
{
    i++;
}
void handler(int sig)
{
    int j = 0;
    while(j < 5)
    {
         j++;
         add();
    }
}
int main()
{
    signal(2, handler);
    int count = 0;
    while(count < 6)
    {
    sleep(1);
    count += 1;
    add();
    printf("i = %d\n", i);
    }
    return 0;
}

add()函数就是一个不可重入函数,它在没有收到信号和收到信号时的结果完全不同。

可重入函数需要满足的条件
  1. 不使用全局变量或者静态变量
  2. 不使用malloc或者new开辟新空间
  3. 不能调用不可重入函数
  4. 所有数据都由函数的调用者提供
  5. 使用本地数据,或者通过制作全局数据的本地拷贝保护全局数据
不可重入函数符合以下条件之一
  1. 调用malloc或者free函数,因为malloc函数是用全局链表管理堆的
  2. 调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构
  3. 使用了静态数据结构

可重入函数和线程安全的联系和区别:
  1. 线程安全是在多线程情况下引发的,而可重入函数可以在只有一个线程的情况下发生
  2. 线程安全不一定是可重入的,而可重入函数一定是线程安全的
  3. 一个函数有全局变量,这个函数既不是线程安全的也不是可重入的
  4. 如果一个函数的数据全是自己栈空间的数据,那么这个函数是线程安全的,也是可重入的
  5. 如果对临界资源进行加锁,则这个函数是线程安全的,如果是可重入函数加锁的话,锁不能被释放,会产生死锁,所以仍是不可重入函数
  6. 线程安全函数能够让不同的线程访问同一块地址空间,而可重入函数要求不同的执行流重复的操作不影响结果,使每次操作结果都相同
参考文章:http://blog.csdn.net/scenlyf/article/details/52074444

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值