[collect]理解可重入与线程安全


=Start=

缘由:

有些概念记得不清楚,经常混淆,还是因为没有实际遇到并处理过,先整理一下,方便以后查找方便。

正文:

参考解答:
# 可重入函数

可重入函数,与多线程无关,即可重入概念并不依赖于多线程,可重入的提出是依据单一线程提出来的,当然,多线程可重入是他的扩展。一个函数被同一个线程调用2次以上,得到的结果具有可再现性(多次调用函数,得到的结果是一样的)。那么我们说这个函数是可重入的。

可重入,并不一定要是多线程的。可重入只关注一个结果可再现性。在APUE中,可函数可重入的概念最先是在讲signal的handler的时候提出的。此时进程(线程)正在执行函数fun(),在函数fun()还未执行完的时候,突然进程接收到一个信号sig, 此时,需要暂停执行fun(),要转而执行sig信号的处理函数sig_handler(),那么,如果在sig_handler()中,也恰好调用了函数fun().信号的处理是以软终端的形式进行的,那么,当sig_handler()执行完返回之后,CPU会继续从fun()被打断的地方往下执行。这里讲的比较特殊,最好的情况是,进程中调用了fun(),函数,信号处理函数sig_handle()中也调用了fun()。如果fun()函数是可重入的,那么,多次调用fun()函数就具有可再现性。从而,两次调用fun()的结果是正确的预期结果。非可重入函数,则恰好相反。

简而言之,可重入函数,描述的是函数被多次调用但是结果具有可再现性。

如果fun(),中,使用了static变量、返回全局变量、调用非可重入函数等等,带有全局性的操作,都将会导致2次以上调用fun()的结果的不可再现性(当然,有些时候使用了static、全局变量等等,不一定导致调用结果不可再现性)。只要使调用结果具有可再现性,那么该函数就是可重入的。

为了保证函数是可重入的,需要做到以下几点:

  1. 不在函数内部使用静态或者全局数据;
  2. 不返回静态或者全局数据,所有的数据都由函数调用者提供;
  3. 使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据;
  4. 如果必须访问全局数据,使用互斥锁来保护;
  5. 不调用不可重入函数;

# 线程安全

If a function can be safely called by multiple threads at the same time, we say that the function is thread-safe.

上面一段话是APUE中的解释,如果一个函数能够安全的同时被多个线程调用而得到正确的结果,那么,我们说这个函数是线程安全的。所谓安全,一切可能导致结果不正确的因素都是不安全的调用。

线程安全,是针对多线程而言的。那么和可重入联系起来,我们可以断定,可重入函数必定是线程安全的,但是线程安全的,不一定是可重入的。不可重入函数,函数调用结果不具有可再现性,可以通过互斥锁等机制,使之能安全的同时被多个线程调用,那么,这个不可重入函数就是转换成了线程安全。

线程安全,描述的是函数能同时被多个线程安全的调用,并不要求调用函数的结果具有可再现性。也就是说,多个线程同时调用该函数,允许出现互相影响的情况,这种情况的出现需要某些机制比如互斥锁来支持,使之安全。

 

参考链接:

=END=


《 “[collect]理解可重入与线程安全” 》 有 3 条评论

  1. C语言线程安全:不可重入函数汇总
    https://vimsky.com/article/3185.html
    `
    多线程程序中,线程安全是必须要考虑的因素。C语言中大部分函库函数都是线程安全的,但是也有几个常用函数是线程不安全的,也叫不可重入函数。

    线程不安全函数原因浅析
    之所线程不安全,是因为这些系统函数使用了某些全局或者静态变量。我们知道,全局变量和静态变量分别对应内存中的全局变量区和静态存储区,这些区域都是可以跨函数跨线程访问的。一旦在多线程环境中使用,在没有加锁的情况下,对同一段内存块进行并发读写,就会造成segmentfault/coredump之类的问题。关于LINUX内存区域的分析详见:剖析程序的内存布局。

    常见的线程不安全类型有两类:
    1、函数依赖了全局变量,并且会修改全局变量,如rand()的实现每次调用都会修改和读取一个全局的INT。
    2、函数返回了静态变量,如ctime()函数。
    `

  2. “如果fun(),中,使用了static变量、返回全局变量、调用非可重入函数等等,带有全局性的操作,都将会导致2次以上调用fun()的结果的不可再现性(当然,有些时候使用了static、全局变量等等,不一定导致调用结果不可再现性)。只要使调用结果具有可再现性,那么该函数就是可重入的。”

    对于这段话,想请教下博主:比如一个函数只是return 某全局变量的数值,这个函数可以称为“可重入函数嘛”

    • 不可以。因为全局变量的数值可能会变,导致返回的结果不一定。“只要使调用结果具有可再现性,那么该函数就是可重入的”——不满足的就是不可重入的。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注