zoukankan      html  css  js  c++  java
  • 线程安全函数和可重入函数 辨析

    偶然想起之前项目里面遇到的一个操作合成结果翻转导致的画面hung死的问题,一时有点记不清了,后面看了细节之后再补充吧。

    反正借着这个点,思考和总结一下线程安全函数和可重入函数的区别和联系,它们已经在我的白板上待了很长时间了。

    这里补充一下之前那个bug的具体原因:
    首先场景是用户点击gui上的屏幕旋转按钮,这个下面会调用我这边的api,触发合成器进行旋转操作。
    如果用户快速多次点击呢,则有大概率触发死锁。

    在界面交互时点击执行较长时间请求操作时,防止多次点击导致后台重复执行(忽略重复触发)这个地方应该用的是tryLock的机制

    首先,一个重要的结论是:可重入函数一定是线程安全的,但是线程安全函数不一定是可重入的

    reentrant和thread safe的本质的区别就在于,reentrant函数要求即使在同一个线程中任意地进入两次以上,也能正确执行

    我们一级一级的向着可重入函数出发,看看要成为可重入函数需要满足什么条件

    1、首先线程不安全的函数,一定是不可重入的

    这个不用多说了,线程不安全函数,指定是没有处理好对临界资源访问的互斥。

    比如访问一个全局变量,或者使用系统调用,而且没有加锁,那么他就不是线程安全的。

    为什么说不可重入呢,比如这个函数被中断了,中断服务中也用到了这个函数,那这里是不是还是会有问题。

    一般来说,函数库的作者是有必要声明自己的api是否是线程安全的,以及是否有线程安全的版本

    这里补充一下,可重入/不可重入函数的概念
    
    若一个程序或子程序(或函数)可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,
    则称其为可重入(reentrant)的。即当该子程序正在被执行是,执行线程可以再次进入并执行它,仍然获取符合预期的结果

    2、线程不安全的函数可以通过加锁变成线程安全函数

    但是即使加了锁,它也锁不了系统中断,或者信号处理函数,CPU的PC指针直接从mutex.lock()中跳出来,到了signal处理函数中,注意,这里尝试拿锁,结果锁在用户那里,于是就会死锁hung死在这里。因为中断等用户释放锁才能返回,用户等中断退出才能释放

    这是因为一般的mutex也是不可重入的,即使使用可重入锁(递归锁),也可能带来别的问题,因为相当于,两个地方都觉得自己拿到锁了,然后就竞争了。所以,一般情况下,不用递归锁。理由如下:

    递归锁用起来固然简单,但往往会隐藏某些代码问题。比如调用函数和被调用函数以为自己拿到了锁,都在修改同一个对象,这时就很容易出现问题。因此在能使用非递归锁的情况下,应该尽量使用非递归锁,因为死锁相对来说,更容易通过调试发现。程序设计如果有问题,应该暴露的越早越好

    一个著名的例子: printf线程安全,但是不可重入

    3、可重入函数是线程安全的

    这里有个限制条件,那就是满足以下条件的函数我们称之为可重入函数:

    • 不能含有静态或全局非常量数据。
    • 不能返回静态或全局非常量数据的地址
    • 不能调用标准 I/O
    • 调用的函数也必须是可重入的
    • 没有动态分配或释放堆资源

    因为有下面一个恶心人的例子,看起来可重入的函数,但是线程不安全,但是因为它用了全局非常量数据,我倾向于不认可这货是个可重入函数

    下面这个函数就很神奇:

    int t;

    void swap(int *x, int *y)

    {

    int s;

    s = t;

    t = *x;

    *x = *y;

    *y = t;

    t = s;

    }

    如果同时在正常流程和信号处理程序中都调用了swap,不会造成错误的结果。因为无论信号在哪里发生并调用swap函数,最后都会把全局变量t进行恢复然后返回到正常流程。所以当正常流程执行完成后,全局变量t保持不变。这样说来,这个函数是可重入的。

    但在多线程环境就有错误,首先线程A执行swap调用到 t = *x 语句,把全局变量t改变了。

    然后线程B调用swap把全局变量t保存到变量s,然后切换到线程A把swap函数全部执行,最后切换到线程B执行完成,就会把全局变量t的值改变了(变成线程A中的*x)。这样说来,这个函数不是线程安全的。

    作者:林嘉亮
    链接:https://www.zhihu.com/question/21526405/answer/469884796
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    SpringMVC + Spring + MyBatis 学习笔记:遭遇order by 排序问题
    SpringMVC + Spring + MyBatis 学习笔记:SpringMVC和Spring一同工作的时候,AOP事务管理不起作用的解决方法
    SpringMVC + Spring + MyBatis 学习笔记:提交数据遭遇基础类型和日期类型报400错误解决方法
    SpringMVC + Spring + MyBatis 学习笔记:为MyBatis增加打印SQL功能 (最简化配置)
    [转]大部分人努力程度之低,根本轮不到拼天赋
    String内存陷阱简介
    同为程序员 为什么我的工资最低
    在程序员的眼里,用户是这样使用他们开发的软件的
    POI怎么和项目结合起来使用
    uploadify
  • 原文地址:https://www.cnblogs.com/Arnold-Zhang/p/15706170.html
Copyright © 2011-2022 走看看