码迷,mamicode.com
首页 > 编程语言 > 详细

线程安全与可重入函数

时间:2016-05-06 19:51:22      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:程序   真子集   而且拓展   

  1. 定义

    (1).线程安全函数:一般说来,一个函数被称为线程安全的,当它被多个并发线程反复调用时,它会一直产生正确的结果。


    (2).可重入:程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),这样便发生了所谓的重入。此时如果foo()能够正确的运行,而且处理完成后,之前暂停的foo()也能够正确运行,则说明它是可重入的。


    (3).拓展: 

    1).如果一个函数中用到了全局或静态变量,那么它不是线程安全的,也不是可重入的; 

    2).如果我们对它加以改进,在访问全局或静态变量时使用互斥量或信号量等方式加锁,则可以使它变成线程安全的,但此时它仍然是不可重入的,因为通常加锁方式是针对不同线程的访问,而对同一线程可能出现问题; 

    3).如果将函数中的全局或静态变量去掉,改成函数参数等其他形式,则有可能使函数变成既线程安全,又可重入。


  2. 联系

    可重入函数是线程安全函数的一个真子集。即可重入函数是线程安全函数,但是反过来,线程安全函数未必是可重入函数。


  3. 区别

    (1)解决问题:

    a.可重入函数要解决的问题是,不在函数内部使用静态或全局数据,不返回静态或全局数据,也不调用不可重入函数。

    b.线程安全函数要解决的问题是,多个线程调用函数时访问资源冲突。


    (2)确保措施

  a.确保线程安全的措施是:线程安全函数不使用共享数据(全局、静态或堆)或者对共享数据实施同步机制保护。

  b.保障可重入的措施:不共享数据并且不调用不可重入函数。

    (1)不要使用static变量和全局变量,坚持只用局部变量;

    (2)若必须访问全局变量,利用互斥信号量来保护全局变量;

    (3)获取得知哪些系统调用是可重入的,在多任务处理程序中都使用安全的系统调用;

    (4)不调用其它任何不可重入的函数;

    (5)谨慎使用堆栈malloc/new。


  (3)变化

   函数如果使用静态变量,通过加锁后可以转成线程安全函数,但仍然有可能不是可重入的,比如    strtok。strtok是既不可重入的,也不是线程安全的。加锁的strtok不是可重入的,但线程安全。而    strtok_r既是可重入的,也是线程安全的。


4. 函数的线程不安全与不可重入的原因

(1)任何线程不安全问题的根源都是“共享数据”所以,不使用任何共享数据的函数(即:可重入函  数)肯定是线程安全的。

(2)不可重入函数的原因在于:

 a. 已知它们使用静态数据结构
 b. 它们调用malloc和free.
 因为malloc通常会为所分配的存储区维护一个链接表,而插入执行信号处理函数的时候,进程可能正  在修改此链接表。
 c. 它们是标准IO函数.
 因为标准IO库的很多实现都使用了全局数据结构

(3)线程安全函数不一定是可重入函数,因为即使有线程有共享数据,线程被并发调用的时候也可以使  其结果正确--通过同步操作保证正确性 

  共享数据可以是:

  1. 函数把返回结果放到一个公共的位置

  2. 由调用者传入的线程间共享的指针变量或者引用变量

  3. 函数内部本来就会使用的共享静态变量


4. 补充

(1)常见的不可重入函数有:
printf --------引用全局变量stdout
malloc --------全局内存分配表
free    --------全局内存分配表


(2)不可重入的解决方举例(printf)

例如,程序正在调用printf输出,但是在调用printf时,出现了信号,对应的信号处理函数也有printf语句,就会导致两个printf的输出混杂在一起。
如果是给printf加锁的话,同样是上面的情况就会导致死锁。对于这种情况,采用的方法一般是在特定的区域屏蔽一定的信号。
屏蔽信号的方法:
1> signal(SIGPIPE, SIG_IGN); //忽略一些信号
2> sigprocmask()
sigprocmask只为单线程定义的
3> pthread_sigmask()
pthread_sigmasks可以在多线程中使用





本文出自 “sunshine225” 博客,请务必保留此出处http://10707460.blog.51cto.com/10697460/1770763

线程安全与可重入函数

标签:程序   真子集   而且拓展   

原文地址:http://10707460.blog.51cto.com/10697460/1770763

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!