Linux下线程安全与可重入函数

来源:互联网 发布:pcb 合拼算法 编辑:程序博客网 时间:2024/04/28 03:24

本文参考《深入理解计算机系统》原书第三版第12章 并发编程
1 线程安全的概念
   一个函数被称为线程安全的(thread-safe),当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。如果一个函数不是线程安全的,我们就说它是线程不安全的(thread-unsafe)。
2 四个线程不安全的函数类
  1) 不保护共享变量的函数。当我们定义一个全局变量,然后创建多个线程进行对其进行++操作,如果我们不对这个变量进行类似P和V的操作进行保护,就会得到一些意料之外的结果。因为++操作并不是原子性的,该操作需要多行汇编代码实现。所以要进行保护才能对其正确操作。优点:不需要修改调用程序,缺点:使执行速率变慢。
  2) 保持跨越多个调用的状态的函数。多个线程调用这个函数,导致我们无法获得想要的数据。例如rand函数是线程不安全的,因为它当前调用的结果依赖于前次调用的中间结果。当多线程调用时,我们便无法获取一个预期的随机序列。解决方法:重写这个函数,使这个函数不依赖static数据,依赖调用者的传参。缺点:麻烦,易出错。
  3) 返回指向静态变量的函数。例如ctime函数,将计算结果存储在一个static变量中,然后返回一个指向这个变量的指针。当多线程调用时会把另一个线程产生的数据覆盖掉。 解决办法:重写这个函数,不共享变量,储存介质由使用者提供;或者使用加锁-复制技术,对需要调用的函数,以及复制的函数(将调用函数的结果复制到一个私有变量)进行加锁。
  4) 调用线程不安全的函数。假设当前进程为f,当其调用一个线程不安全的函数时,那么它是安全的吗?当调用为 2) 时,它必不安全,只能修改源函数;当调用1)或3)时,只要对1)或3)进行加锁复制,那么它就是安全的。
3 可重入函数
  当它们被多个线程调用时,不会引用任何共享数据,这就是可重入函数。可重入函数允许运行中途被打断,而不可重入函数打断后,便不可以得到正确的结果。
  1) 显示可重入函数。如果所有函数的参数都是传值传递的(没有指针),并且所有的数据引用都是本地的自动栈变量(也就是说没有引用静态或全局变量),那么函数就是显示可重入的,也就是说不管它被如何调用,我们都可断言它是可重入的.
  2) 隐式可重入函数。允许显示可重入函数中的一些参数是引用传递(传指针),便可得到一个隐式可重入函数。也就是说,如果在调用线程小心地传递指向非共享数据的指针时,它是可重入的。
  可重入函数的特点:不适用全局或静态变量,如果使用,需要进行复制保护。不开辟堆上的空间。
4 线程安全与可重入函数的关系
  关系如下图:

原创粉丝点击