可重入和线程安全

线程安全这个词对我来说已经不是很陌生的了,但是遇到一个叫做可重入函数的词,它给我的感觉和线程安全是这么的相近,但既然拿出来了,肯定是有区别的,下面就说说他们之间的区别和联系。

要先解释这两个词语才行。

线程安全:似乎是在牛客网刷题的时候看到一个正确的选项说的是,线程安全问题都是由全局变量及静态变量引起的。

可重入函数:按我现在的理解就是,因为不同的执行流执行同一个函数,导致函数的执行顺序和预期的函数执行顺序不同导致执行逻辑不正确,得不到正确的结果

这么一看,可重入函数和线程安全似乎没有什么大的关系,下面给出两个比较典型的例子,来看一下。

线程安全:先说一下环境,如下面的代码表示的一样,a和b都是静态变量(也就是说是全局可见的),两段代码都在同一个项目中

1 static int a;
2 static int b;
3 a=10;//!!!!!!!!
4 b=a;
a=5;//!!!!!!
a=b;

看着两段代码似乎没什么关系,各自执行各自的,但是当有两个线程(都属于同一个进程)同时跑这个程序的时候,问题就出现了,也就是线程A和线程B的执行顺序:

线程A:a=10;

线程B:a=5;

线程A:b=a;

线程B:a=b;

本来b是要等于10的,但由于线程B先执行了a=5导致b最终结果编程5出现了错误。这就是一个简单的线程安全的例子。

可重入函数:常见的情况是,程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理 函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),这样便发生了所谓的重入,那么这么做的结果会变成什么样子呢?

当执行完第一次insert的时候,假设此时发生了中断,导致系统陷入内核,当系统准备从内核态切换到用户态的时候检查到此时有信号待处理,于是调用信号处理函数(就是注册好的signalhandler啦),但是恰好注册的函数中有一次对insert进行了调用,这就相当于有两个人同时进入了一个小黑屋里一样,有多个执行流在对该函数进行操作,最终导致内存泄漏,丢失了对node2的控制。

这样看来,线程安全和可重入的问题都是因为执行流的问题引起的了。

很显然,如果一个函数是可重入函数,那么它一定是线程安全的,但是如果一个函数是线程安全的,它不一定是可重入函数,就跟上图中举得例子一样的,很明显insert函数是线程安全的,但是它并不是可重入函数

那么究竟什么是可重入函数的定义呢?

在多线程或有异常控制流的情况下,当某个函数运行到中途时,控制流(也就是当前指令序列)就有可能被打断而去执行另一个函数.而"另一个函数"很有可能是它本身.,如果在这种情况下不会出现问题,比如说数据或状态不会被破坏,行为确定。那么这个函数就被称做"可重入"的.

可重入函数需要满足什么条件呢?

  • 不能使用malloc系列函数,因为malloc函数内部是通过全局链表实现的
  • 不可以调用标准I/O库函数,这些库函数很多都不是可重入的
  • 肯定不能有全局或者静态变量,否则连线程安全都不满足了
时间: 2024-12-28 22:05:54

可重入和线程安全的相关文章

可重入与线程安全(大多数Qt类是可重入,非线程安全的)

可重入与线程安全 在Qt文档中,术语“可重入”与“线程安全”被用来说明一个函数如何用于多线程程序.假如一个类的任何函数在此类的多个不同的实例上,可以被多个线程同时调用,那么这个类被称为是“可重入”的.假如不同的线程作用在同一个实例上仍可以正常工作,那么称之为“线程安全”的. 大多数c++类天生就是可重入的,因为它们典型地仅仅引用成员数据.任何线程可以在类的一个实例上调用这样的成员函数,只要没有别的线程在同一个实例上调用这个成员函数.举例来讲,下面的Counter 类是可重入的: class Co

可重入和线程安全简单介绍

可重入和线程安全 可重入和线程安全这两个术语,经常出现在计算机编程中,用于指明类和函数在多线程程序中的使用. 可重入:若一个程序或子程序可以“安全的被并行执行(Parallel computing)”,则称其为可重入(reentrant或re-entrant)的. 若一个函数是可重入的,则该函数: 1.不能含有静态(全局)非常量数据. 2.不能返回静态(全局)非常量数据的地址. 3.只能处理由调用者提供的数据. 4.不能依赖于单实例模式资源的锁. 5.不能调用(call)不可重入的函数. 线程安

Writing Reentrant and Thread-Safe Code(译:编写可重入和线程安全的代码)

Writing Reentrant and Thread-Safe Code 编写可重入和线程安全的代码 (http://www.ualberta.ca/dept/chemeng/AIX-43/share/man/info/C/a_doc_lib/aixprggd/genprogc/writing_reentrant_thread_safe_code.htm) In single-threaded processes there is only one flow of control. The

可重入与线程安全

看了好多文章,觉得这俩概念很容易混淆.在这里先总结一下自己的理解. 维基百科对可重入的定义是:  若一个程序或子程序可以"安全的被并行执行(Parallel computing)",则称其为可重入(reentrant或re-entrant)的. 可重入的概念是在单线程操作系统的时代提出的.可重入会影响函数的外部接口,而线程安全只关心函数的实现. 可重入函数未必是线程安全的,线程安全的函数也未必是可重入的.例如: 例1: 一个函数打开某个文件并读入数据.这个函数是可重入的,因为它的多个实

线程安全和可重入函数

一.线程安全 1.线程安全函数:C语言中局部变量是在栈中分配的,任何未使用静态数据或其他共享资源的函数都是线程安全的. (1)对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量.局部静态变量.分配于堆的变量都是共享的,即是非线程安全的. (2) 在对这些共享变量进行访 问时,如果要保证线程安全,则必须通过加锁的方式. 2.线程安全的:                   如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的.                  

线程安全和可重入函数的区别与联系

线程安全: 一般来说,一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果.就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用.不会出现数据不一致或者数据污染. 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和 运行的结果是一样的,而且其他的变量的值也和预期的是一样  的, 就是线程安全的. 或者说:一个类或者程序所提供的接口对于线程来说

linux可重入、异步信号安全和线程安全

一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕获到信号时进程正在执行的正常指令序列(这和当一个硬件中断发生是所发生的事情相似.)但是在信号处理器里,我们并不知道当信号被捕获时进程正在执行哪里的代码. 如果进程正使用malloc在它的堆上分配额外的内存,而此时由于捕捉到信号而插入执行该信号处理程序,其中又调用了malloc,这会

函数的可重入性、线程安全函数、异步信号安全函数

重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰.,常见的情况是,程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),这样便发生了所谓的重入.此时如果foo()能够正确的运行,而且处理完

可重入函数与线程安全问题

线程安全函数 确保线程安全:        要确保函数线程安全,主要需要考虑的是线程之间的共享变量.属于同一进程的不同线程会共享进程内存空间中的全局区和堆,而私有的线程空间则主要包括栈和寄存器.因此,对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量.局部静态变量.分配于堆的变量都是共享的.在对这些共享变量进行访问时,如果要保证线程安全,则必须通过加锁的方式. 线程不安全的后果:        线程不安全可能导致的后果是显而易见的--共享变量的值由于不同线程的访问,可能发生不可