& amp; amp; quot;可重入& amp; amp; amp; quot;和& amp; amp;“线程安全& amp; amp; amp; amp; amp; amp; amp; amp; quot;”是两个概念,不要混淆

每个人都认为使用printf在多任务程序中打印一些信息是一件很快乐的事情。

如果幸运的话,偶尔会犯一些错误或随机代码也不是什么大问题。

如果您不走运,您可能会挂断电话并陷入困境。

,那么这是什么原因呢?今天的文章应该能够帮助您解决大多数问题。

01两个概念1.可重入函数多任务系统中的每个进程或线程都由多个执行流同时运行。

当执行流在同一时间(主要是由于中断)同时进入同一函数时,它不会引起。

如果函数的结果不确定或错误,则该函数可被视为可重入的。

上图中的信号通常是由于中断和其他原因而产生的。

在我们的多任务系统中,中断总是随机发生的。

一旦线程或进程被中断,它将执行消息处理,而这恰好是这次。

线程执行的操作与信号处理相同,例如malloc,它们都共享相同的资源(全局堆空间)。

当信号处理返回到原始执行流程时,它会受到信号处理重写的影响。

例如,重入问题导致malloc分配相同的内存区域,或其他数据篡改,锁定等,因此该函数不是重复输入的。

2.线程安全。

多个线程同时运行并执行相同的代码,而不会影响运行结果。

我们认为它是线程安全的。

为了线程安全,通常可以通过添加互斥锁来解决争斗。

当然,如果您不使用共享资源(例如全局变量,静态变量等),则它们基本上是线程安全的。

实际上,从表面上看,这两个概念之间并没有太大区别,无非就是运行同一段代码,这会导致不确定的结果。

3. VS再考虑一下。

实际上,这两个概念侧重于不同的层次。

可重入函数要求执行相同的执行流程而不会受到影响,并且线程安全仅是线程级别的要求。

因此,重新进入的要求比线程安全性更为严格。

可重入必须是线程安全的,并且线程安全不一定是可重入的。

下图显示了它们之间的关系:02非可重入死锁让我们简要分析一下。

非可重入死锁的问题:在上图中,我们向函数添加了互斥锁(与递归锁无关),这是线程安全的,但只是锁定了共享资源部分,发生了随机中断信号处理, turn执行信号处理功能,并且在信号处理中也执行相同的功能代码。

这时,资源被锁定,必须等待调用Fuction函数的线程被释放,但是该线程正在等待信号处理访问,最后是死锁。

凉爽的!当然,您可以使用递归锁进行处理,这在正常设计中需要避免。

那时,对于某些需要调用外部库的设计,您只能选择递归锁。

03重入者认可。

老实说,对于许多玩RTOS的人来说,直接关闭中断并打开关键的中断资源保护基本上可以告别一些不可重入的问题,此类操作将影响多任务的并发执行,但是如果您只需添加几个锁,您仍然需要注意程序中不可重入的问题。

这里的非可重入问题不能完全概括以下几点:1.标准IO函数将使用全局数据结构,例如printf函数:因为使用了全局标准输出stdout,所以线程不安全并且不能重入。

2. malloc和free:这两个函数在全局堆空间上运行。

如果有锁,则它是线程安全的,但不能重入。

3.访问全局和静态资源将导致线程不安全。

例如,某些函数使用静态缓冲区。

您可以使用本地副本加关键区域进行保护,并尝试使用本地变量。

4.调用非可重入或线程不安全的函数也将继承相应的特征。