fork(应该是)对于线程程序中的信号处理程序来说是安全的吗?

2023-12-23

我真的不确定 POSIX 对安全性的要求fork在存在线程和信号的情况下。fork被列为异步信号安全函数之一,但如果库代码可能已注册pthread_atfork处理程序不是异步信号安全的,这是否否定了安全性fork?答案是否取决于运行信号处理程序的线程是否正在使用 atfork 处理程序所需的资源?或者换句话说,如果 atfork 处理程序使用同步资源(互斥体等)但是fork从从不访问这些资源的线程中执行的信号处理程序调用,程序是否符合要求?

基于这个问题,如果使用建议的习惯用法在系统库内部实现“线程安全”分叉pthread_atfork(获取 prefork 处理程序中的所有锁并释放父子 postfork 处理程序中的所有锁),然后是fork在线程程序中使用信号处理程序是否安全?处理信号的线程是否有可能正在调用malloc or fopen/fclose并持有全局锁,导致期间死锁fork?

最后,即使fork在信号处理程序中是安全的,是否安全fork在信号处理程序中,然后从信号处理程序返回,或者调用fork在信号处理程序中总是需要随后调用_exit或其中之一exec信号处理程序返回之前的函数系列?


尽力回答所有子问题;我很抱歉其中一些内容比理想情况下更模糊:

如果有一个 库代码具有的可能性 注册 pthread_atfork 处理程序 这不是异步信号安全的, 这否定了fork的安全性吗?

是的。这分叉文档 http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html明确提到这一点:

   When the application calls fork() from a signal handler and any of the
   fork handlers registered by pthread_atfork() calls a function that is
   not asynch-signal-safe, the behavior is undefined.

当然,这意味着你实际上不能使用pthread_atfork()其预期目的是使多线程库对认为它们是单线程的进程透明,因为没有一个 pthread 同步函数是异步信号安全的;这在规范中被标记为缺陷,请参阅http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt(搜索“L16723”)。

做 答案取决于是否 信号处理程序所在的线程 跑步可能会在中间 使用 atfork 的资源 处理程序需要?或者说不同的 方式,如果 atfork 处理程序使用 同步资源(互斥锁、 等)但是 fork 是从 a 调用的 在a中执行的信号处理程序 从不访问这些的线程 资源,程序是否符合要求?

严格来说答案是否定的,因为根据规范,函数要么是异步信号安全的,要么不是;不存在“在某些情况下安全”的概念。在实践中,您很可能会侥幸逃脱,但您可能会受到笨重但正确的实现的影响,该实现没有按照您期望的方式分区其资源。

基于这个问题,如果 实现了“线程安全”分叉 在系统库内部使用 pthread_atfork 建议的习惯用法 (获取预叉中的所有锁 处理程序并释放两者中的所有锁 父子后叉 处理程序),那么 fork 是否安全 在线程中使用信号处理程序 程序?是不是有可能 处理信号的线程可能位于 调用 malloc 或的中间 fopen/fclose 并持有全局 锁,导致期间死锁 叉?

如果按照这种方式实施,那么你是对的,fork()来自信号处理程序永远不会安全,因为如果调用线程已经持有锁,则尝试获取锁可能会死锁。但这意味着使用这种方法的实现将不符合要求。

以 glibc 为例,它并没有这样做 - 相反,它采用两种方法:第一,它获得的锁是递归的(因此,如果当前线程已经拥有它们,它们的锁计数将简单地增加);此外,在子进程中,它只是单方面覆盖所有锁 - 请参阅摘录nptl/sysdeps/unix/sysv/linux/fork.c:

  /* Reset the file list.  These are recursive mutexes.  */
  fresetlockfiles ();

  /* Reset locks in the I/O code.  */
  _IO_list_resetlock ();

  /* Reset the lock the dynamic loader uses to protect its data.  */
  __rtld_lock_initialize (GL(dl_load_lock));

其中每个resetlock and lock_initialize函数最终调用 glibc 的内部等效函数pthread_mutex_init(),无论是否有任何服务员,都会有效地重置互斥锁。

我认为理论是,通过获取(递归)锁,可以保证没有其他线程会接触数据结构(至少以可能导致崩溃的方式),然后重置各个锁以确保资源不被访问。 t 永久被阻止。 (重置当前线程的锁是安全的,因为现在没有其他线程来争夺数据结构,并且实际上直到使用锁的任何函数返回为止都不会发生)。

我不是 100% 相信这涵盖了所有可能性(尤其是因为如果/当信号处理程序返回时,刚刚被盗锁的函数将尝试解锁它,并且内部递归解锁函数不能防止解锁太多次了!) - 但这似乎是一个可行的方案could构建在异步信号安全递归锁之上。

最后,即使 fork 是安全的 信号处理程序,分叉是否安全 一个信号处理程序,然后从 信号处理程序,或者调用 始终在信号处理程序中分叉 需要随后调用 _exit 或 exec 函数系列之一 在信号处理程序返回之前?

我假设你在谈论子进程? (如果fork()异步信号安全意味着任何事情都应该可以在父级中返回!)

在规范中没有发现任何其他说明(尽管我可能错过了)我相信它应该安全 - 至少,从子级中的信号处理程序返回的意义上来说“安全”并不意味着其本身存在未定义的行为,尽管多线程进程刚刚分叉的事实可能意味着exec*() or _exit()可能是最安全的行动方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

fork(应该是)对于线程程序中的信号处理程序来说是安全的吗? 的相关文章

  • c和java语言中的换行符

    现在行分隔符取决于系统 但在 C 程序中我使用 n 作为行分隔符 无论我在 Windows 还是 Linux 中运行它都可以正常工作 为什么 在java中 我们必须使用 n 因为它与系统相关 那么为什么我们在c中使用 n 作为新行 而不管我
  • 如何在 C++ 中的文件末尾添加数据?

    我已按照网上的说明进行操作 此代码应该将输入添加到文件 数据库 的末尾 但当我检查时 数据会覆盖现有数据 请帮忙 这是我的代码 int main string name string address string handphone cou
  • 如何检查QProcess是否正确执行?

    QProcess process sdcompare QString command sdcompare QStringList args sdcompare command sdcompare diff args sdcompare lt
  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • 将 System.Windows.Input.KeyEventArgs 键转换为 char

    我需要将事件参数作为char 但是当我尝试转换 Key 枚举时 我得到的字母和符号与传入的字母和符号完全不同 如何正确地将密钥转换为字符 这是我尝试过的 ObserveKeyStroke this new ObervableKeyStrok
  • 无法在 Windows 运行时组件库的 UserControl 中创建依赖项属性

    我想在用户控件内创建数据可绑定属性 这个用户控件包含一个 Windows 运行时组件 项目 我使用下面的代码来创建属性 public MyItem CurrentItem get return MyItem GetValue Current
  • 如何在 C# 中定义文本框数组?

    您好 当我在 Windows 申请表上创建文本框时 我无法将其命名为 box 0 box 1 等 我这样做的目的是因为我想循环使用它们 其实我发现TextBox array firstTextBox secondTextBox 也有效
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • ASP.NET:获取自 1970 年 1 月 1 日以来的毫秒数

    我有一个 ASP NET VB NET 日期 我试图获取自 1970 年 1 月 1 日以来的毫秒数 我尝试在 MSDN 中寻找方法 但找不到任何东西 有谁知道如何做到这一点 从 NET 4 6 开始 该方法ToUnixTimeMillis
  • 将 Excel 导入到 Datagridview

    我使用此代码打开 Excel 文件并将其保存在 DataGridView 中 string name Items string constr Provider Microsoft Jet OLEDB 4 0 Data Source Dial
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当

随机推荐