可重入性 、异步信号安全 和 线程安全 辨析

本文详细探讨了可重入性和线程安全性在函数设计中的应用与区别,包括它们在多线程环境下的行为特征及如何实现线程安全和可重入函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可重入性函数( Reentrant Function)

 

    可重入与线程安全是两个独立的概念, 都与函数处理资源的方式有关。

  • 首先,可重入和线程安全是两个并不等同的概念,一个函数可以是可重入的,也可以是线程安全的,可以两者均满足,可以两者皆不满组(该描述严格的说存在漏洞,参见第二条)。
  • 其次,从集合和逻辑的角度看,可重入是线程安全的子集,可重入是线程安全的充分非必要条件。可重入的函数一定是线程安全的,然过来则不成立。
  • 第三,POSIX 中对可重入和线程安全这两个概念的定义:

        Reentrant Function:A function whose effect, when called by two or more threads,is guaranteed to be as if the threads each executed thefunction one after another in an undefined order, even ifthe actual execution is interleaved.

 

        Thread-Safe Function:A function that may be safely invoked concurrently by multiple  threads.

 

 

         Async-Signal-Safe Function: A function that may be invoked, without restriction fromsignal-catching functions. No function is async-signal -safe unless explicitly described as such.

 

       以上三者的关系为:可重入函数 必然 是 线程安全函数 和 异步信号安全函数;

                                     线程安全函数不一定是可重入函数。 


     可重入与线程安全的区别体现在能否在signal处理函数中被调用的问题上,可重入函数在signal处理函数中可以被安全调用,因此同时也是Async-Signal-Safe Function;而线程安全函数不保证可以在signal处理函数中被安全调用,如果通过设置信号阻塞集合等方法保证一个非可重入函数不被信号中断,那么它也是Async-Signal-Safe Function

     值得一提的是POSIX 1003.1的System Interface缺省是Thread-Safe的,但不是Async-Signal-Safe的。Async-Signal-Safe的需要明确表示,比如fork ()和signal()。

 

    一个非可重入函数通常(尽管不是所有情况下)由它的外部接口和使用方法即可进行判断。例如:strtok()是非可重入的,因为它在内部存储了被标记分割的字符串;ctime()函数也是非可重入的,它返回一个指向静态数据的指针,而该静态数据在每次调用中都被覆盖重写。

 

    一个线程安全的函数通过加锁的方式来实现多线程对共享数据的安全访问。线程安全这个概念,只与函数的内部实现有关,而不影响函数的外部接口。C语言中,局部变量是在栈上分配的。因此,任何未使用静态数据或其他共享资源的函数都是线程安全的。

 

   目前的AIX版本中,以下函数库是线程安全的:

         * C标准函数库

         * BSD兼容的函数库

 

 

    使用全局变量(的函数)是非线程安全的。这样的信息应该以线程为单位进行存储,这样对数据的访问就可以串行化。一个线程可能会读取由另外一个线程生成的错误代码。在AIX中,每个线程有独立的errno变量。

 

最后让我们来构想一个线程安全但不可重入的函数:

     假设函数func()在执行过程中需要访问某个共享资源,因此为了实现线程安全,在使用该资源前加锁,在不需要资源解锁。

     假设该函数在某次执行过程中,在已经获得资源锁之后,有异步信号发生,程序的执行流转交给对应的信号处理函数;再假设在该信号处理函数中也需要调用函数func(),那么func()在这次执行中仍会在访问共享资源前试图获得资源锁,然而我们知道前一个func()实例已然获得该锁,因此信号处理函数阻塞——另一方面,信号处理函数结束前被信号中断的线程是无法恢复执行的,当然也没有释放资源的机会,这样就出现了线程和信号处理函数之间的死锁局面。

     因此,func()尽管通过加锁的方式能保证线程安全,但是由于函数体对共享资源的访问,因此是非可重入。

 

改写函数库

下面强调了将现存函数库改写为可重入和线程安全版本的主要步骤,只适用于C语言的函数库。

 

    * 识别出由函数库导出的所有全局变量。这些全局变量通常是在头文件中由export关键字定义的。

      导出的全局变量应该被封装起来。每个变量应该被设为函数库所私有的(通过static关键字实现),然后创建全局变量的访问函数来执行对全局变量的访问。

 

    * 识别出所有静态变量和其他共享资源。静态变量通常是由static关键字定义的。

       每个共享资源都应该与一个锁关联起来,锁的粒度(也就是锁的数量),影响着函数库的性能。为了初始化所有锁,可能需要一个仅被调用一次的初始化函数。

 

    * 识别所有非可重入函数,并将其转化为可重入。参见函数可重入化

 

    * 识别所有非线程安全函数,并将其转化为线程安全。参见函数线程安全化。

 

 

 使用非线程安全函数的解决方法

 

    通过某种解决方法,非线程安全函数是可以被多个线程调用的。这在某些情况下或许是有用的,特别是当在多线程程序中使用一个非线程安全函数库的时候——或者是出于测试的目的,或者是由于没有相应的线程安全版本可用。这种解决方法会增加开销,因为它需要将对某个或一组函数的调用进行串行化。

 

 

  • 使用作用于整个函数库的锁,在每次使用该函数库(调用库中的某个函数或是访问库中的全局变量)时加锁,如下面的伪代码所示:

      

              /* this is pseudo-code! */

      

              lock(library_lock);

              library_call();

              unlock(library_lock);

      

              lock(library_lock);

              x = library_var;

             unlock(library_lock);

 

 

      该解决方法有可能会造成性能瓶颈,因为在任意时刻,只有一个线程能任意的访问或是用该库。只有在该库很少被使用的情况下,或是作为一种快速的实现方式,该方法才是可接受的。

 

  • 使用作用于单个库组件(函数或是全局变量)或是一组组件的锁,如下面的伪代码所示:

 

            /* this is pseudo-code! */

      

            lock(library_moduleA_lock);

            library_moduleA_call();

            unlock(library_moduleA_lock);

        

            lock(library_moduleB_lock);

            x = library_moduleB_var;

            unlock(library_moduleB_lock);

 

      这种方法与前者相比要复杂一些,但是能提高性能。

 

    由于该类解决方式只应该在应用程序而不是函数库中使用,可以使用互斥锁(mutex)来为整个库加锁。

      

 

标题基于SpringBoot的蛋糕烘焙分享平台研究AI更换标题第1章引言介绍蛋糕烘焙分享平台的研究背景、意义、现状以及论文的方法创新点。1.1研究背景与意义分析蛋糕烘焙行业的现状,阐述分享平台的重要意义。1.2国内外研究现状综述国内外在蛋糕烘焙分享平台方面的研究进展。1.3论文方法及创新点概述论文的研究方法,突出创新点。第2章相关理论介绍SpringBoot框架分享平台开发的相关理论。2.1SpringBoot框架概述简述SpringBoot框架的特点、优势应用场景。2.2分享平台技术基础阐述分享平台开发所需的技术基础,如前后端分离、数据库设计等。2.3用户行为分析理论介绍用户行为分析的基本理论方法,为平台功能设计提供指导。第3章平台需求分析对蛋糕烘焙分享平台进行需求分析,明确平台功能能要求。3.1目标用户群体分析分析平台的目标用户群体,了解其需求特点。3.2功能需求分析详细分析平台应具备的功能,如用户注册、烘焙教程发布、互动交流等。3.3能需求分析对平台的能要求进行分析,确保平台的稳定可扩展。第4章平台设计根据需求分析结果,设计蛋糕烘焙分享平台的整体架构详细功能。4.1平台架构设计设计平台的整体架构,包括前后端分离、数据库设计等。4.2功能模块设计详细设计平台的功能模块,如用户管理、内容管理、互动交流模块等。4.3数据库设计根据平台需求,设计合理的数据库表结构数据字典。第5章平台实现与测试介绍平台的实现过程,包括环境搭建、编码实现测试等环节。5.1环境搭建与配置搭建开发环境,配置必要的软件工具。5.2编码实现按照设计要求,编写平台的前后端代码。5.3平台测试与优化对平台进行测试,发现并解决问题,优化平台能。第6章结论与展望总结论文的研究成果,展望未来的研究方向应用前景。6.1研究结论概括论文的主要研究内容取得的成果。6.2未来研究
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值