【Linux】可重入函数

文章目录

  • 前言
  • 一. 场景
  • 二. 可重入与线程安全
  • 结束语

前言

在Linux中,进程/线程可能因为时间片到达,或者其他中断,或者调用系统,需要从用户态切换到内核态,而内核空间会保存切换前,用户代码执行处的上下文,以便切换回用户态时,可以继续执行原来的代码。
而这样的切换是否会影响代码的执行呢?这就是可重入函数和不可重入函数的概念的产生

【Linux】可重入函数_第1张图片

一. 场景

以下是用户态的一次执行
假如其中有一个链表头插函数的调用
【Linux】可重入函数_第2张图片
在申请结点空间,将node1的指针指向head->next,还没作head的改变时,假如,时间片到了,或者发生了其他的中断,切换到了内核态,捕捉信号。
而信号的执行函数中也同样使用了链表头插的函数,就会再申请一个node2的空间,完成头插后,最终切换回用户态,然后继续执行用户态的链表头插的函数,还会将head->next=node1,这样node2的失效了。就发生了内存泄漏

所以有些函数是不允许执行到一半,而切换到执行流的,这类函数称为不可重入函数,反之为可重入函数

只要函数内部有和文件的交互使用了全局数据,或者有mallocnew,申请了堆数据,那都是不可重入函数
如果一个函数内部只使用局部变量,那么这个函数就可以是可重入函数

可重入/不可重入不是函数的优缺点,只是函数的特性

二. 可重入与线程安全

在多线程时,我们往往需要注意线程的互斥与同步,而也就是在多线程中,不同线程并发运行,经常出现一个线程的动作还没完成,时间片到达,不得不切换成其他线程的情况。
所以线程安全和函数是否可重入有着一定的关系


接下来我们做些总结

  • 线程安全:多个线程并发同一段代码时,不会出现不同的结果。常见对全局变量或者静态变量进行操作,并且没有锁保护的情况下,会出现问题。
  • 重入:同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他执行流再次进入,我们称之为重入。

常见的线程不安全的情况:

  1. 不保护共享变量的函数
  2. 被调用后,状态会发生变化的函数
  3. 返回指向静态变量指针的函数
  4. 调用线程不安全的函数

常见的线程安全的情况:

  1. 每个线程对全局变量或者静态变量只有读取的权限,而没有写入的权限,一般来说是线程安全的
  2. 类或者接口对于线程来说是原子操作
  3. 多个线程之间的切换不会导致该接口执行结果存在二义性

常见的不可重入的情况:

  1. 调用了malloc/free函数,因为malloc函数是使用全局链表来管理堆的
  2. 调用了标准I/O库函数,标准I/O库的很多实现都是以不可重入的方式使用全局数据结构
  3. 可重入函数体内使用了静态的数据结构

常见的可重入的情况:

  1. 不使用全局变量或静态变量
  2. 不使用malloc或者new 开辟空间
  3. 不调用不可重入函数
  4. 不返回静态或者全局数据,所以数据都有函数的调用者提供
  5. 不使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据

可重入与线程安全的联系

  1. 如果调用的函数是可重入函数,那么此时是线程安全
  2. 如果调用的函数是不可重入的,多线程访问就会引发线程安全问题
  3. 如果一个函数中有全局变量,那么这个函数既不是线程安全的,也不是可重入的
  4. 可重入函数是线程安全的一种方式,线程安全不一定是可重入的,但可重入一定是线程安全的

结束语

感谢你的阅读

如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

你可能感兴趣的:(Linux学习笔记,linux,笔记)