【Linux】线程安全与可重入函数

【Linux学习】:在Linux的一段时间学习中,刚开始是模糊的,所以很久没有进行博客的整理,直到最近自己把Linux的学习从前往后回忆与联系清楚了,觉得是时候整理成博客,变为自己的学习笔记了,先从线程安全和可重入函数整理,一方面是趁热打铁,另一方面是在这篇博客中,其实嵌套着前面的学习!


第一部分: 线程安全

最直接的概念,不管是从网上查阅资料还是书上看到的,都会有这么一句:一般来说,一个函数是线程安全的, 当且仅当被多个并发线程反复调用,结果一直是正确的;反之就是不安全的;

一般,我们定义四类线程不安全函数:

1、不保护共享变量的函数;
2、函数状态随着调用改变的函数;
3、返回指向静态变量指针的函数;
4、调用线程不安全函数的函数

:通过对线程安全的定义和对线程安全的判定条件,我们可以想到的就是操作系统中学到的锁的概念,为什么要对临界资源加锁,就是因为线程安全的问题,因为同一进程中的多进程是在同一个地址空间运行的,而多个线程共享的资源就很多了,全局变量,静态变量就是共享的资源,那么如果不对共享资源的访问进行加锁的话,多线程的访问可能会造成错误甚至严重的后果(下面举例说明),那么,含有全局变量的这个函数就是线程不安全的;多个线程之间私有的是各个线程的运行的上下文信息和私有栈,也就是说局部变量不会影响线程安全;

代码说明线程安全问题(LINUX):
比如说,不安全函数条件1,不对全局变量进行保护,我们有两个线程,我们希望一个线程将count加到500,然后另一个线程继续进行count++,我们希望的结果是1000;

代码:
这里写图片描述

:多运行几次你就会发现,会出现结果不是1000的情况,那么这个函数就不是线程安全的;

代码编写时的注意点:

  1. 要验证确实是不同的线程进行了操作,可以使用pthread_self()函数获取线程的tid;
  2. 有时候,我们会把fun函数编写为下面这样,我们发现运行多少次结果都是1000;
void* fun(void* arg)
{
    int i = 0;
    while(i < 500)
    {
        ++i;
        ++count;
        printf("count : %d\n",count);
    }
}

上面这种写法看不出来效果的原因是:因为当前只有这两个进程,++count 体现不出来效果,如果有十几个线程的话,就可以看出来了;

在这里加入一个小知识,也是一道面试题:i++是原子操作吗?

答案是:no ,i++的操作变成汇编的话其实是三个动作:

1.从内存将数据加入寄存器
2.寄存器自加;
3.数据写会内存;

所以不是原子的,在上面的三个动作随时会被切出去;
至于++i,也不是原子的,但是具体的和底层实现有关!;

所以我们定义一个tmp呢,正是为了干扰,将线程不安全体现出来,比如线程1将count加到52的时候,刚用tmp保存了count的值,然后被切出去,进程2又执行count加到200,然后又切到线程1,接下来线程1执行 count = tmp + 1,注意:线程1此时的tmp==52,所以count又被改回去了,这样两个线程之间就产生了干扰,也就是线程不安全;

上面的例子是对全局变量的多线程访问的举例,多个线程运行同一份函数的时候,不能保证每次的运行结果都是预期的。我们知道线程安全是希望多个线程对同一区域进行访问,结果是预期的;

总而言之,线程安全就是多线程对共享资源的访问保持互斥与同步的同时,仍然可以确保每次的结果都是正确的;


第二部分: 重入函数

定义:可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

举个例子:比如一个执行流正在执行一个函数,而此时来了一个信号中断了函数的执行,而去执行信号的自定义动作,恰好这个自定义动作也是这个函数,如果这个信号的执行动作执行完之后,返回原执行函数后不会对原执行结果产生影响,并且不会影响全局和静态变量的话,那么这个函数就是可重入函数;

可重入函数就不 列代码的例子了;
总之,线程安全的函数一定是可重入的;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值