可重入函数和线程安全

可重入函数

当捕捉到信号时,不论进程的主控制流程当前执行到哪儿,都会先跳到信号处理函数中执行,从信号处理函数返回后再继续执行主控制流程。信号处理函数是一个单独的控制流程,因为它和主控制流程是异步的,二者不存在调用和被调用的关系,并且使用不同的堆栈空间。引入了信号处理函数使得一个进程具有多个控制流程,如果这些控制流程访问相同的全局资源(全局变量、硬件资源等),就有可能出现冲突,如下面的例子所示。 如下是不可重⼊入的函数:



  main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节 点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从 main函数调用的insert函数中继续往下执行,先前做第一步之后被打断,现在继续做完第二 步。结果是main函数和sighandler先后 向链表中插入两个节点,而最后只有一个节点真正插入链表中了。 

函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入 (Reentrant) 函数。

在大部分情况下,不可重入的函数修改成可重入的函数时,需要修改函数的对外接口。不可重入的函数不能被多线程的程序调用。一个不可重入的函数,基本上不可能是线程安全的。

线程安全

一个线程安全的函数通过“锁”来保护共享的资源不被并发地访问。“线程安全”仅关心函数的实现,而不影响它的外部接口。

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

使用静态数据或者其它任何共享资源(如文件、终端等)的函数,必须对这些资源加“锁”以实现对它们的串行访问,这样才能成为线程安全的函数。

可重入和线程安全(Thread-Safe)是两个不同的概念:可重入函数一定是线程安全的;线程安全的函数可能是重入的,也可能是不重入的;线程不安全的函数一定是不可重入的。

可重入与线程安全两个概念都关系到函数处理资源的方式。但是,他们有一定的区别。可重入概念会影响函数的外部接口,而线程安全只关心函数的实现。

  • 大多数情况下,要将不可重入函数改为可重入的,需要修改函数接口,使得所有的数据都通过函数的调用者提供。
  • 要将非线程安全的函数改为线程安全的,则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源,使之不会被几个线程同时访问


在一个多线程的程序中,所有的被多线程调用的函数多必须是线程安全的(或可重入的)。注意,不可重入的函数一般都是线程“不安全”的,然而,将它们改写成可重入的同时,一般就会将它们变成线程安全的。

结论:
可重入函数要解决的问题是,不在函数内部使用静态或全局数据,不返回静态或全局数据,也不调用不可重入函数。线程安全函数要解决的问题是,多个线程调用函数时访问资源冲突。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值