C语言 信号处理代码的 Glib 哈希表问题



我有一些系统级代码,每隔一段时间就会触发计时器,并且有一个信号处理程序,可以在这些信号到达时对其进行管理。这工作正常,似乎完全合理。还有两个独立的线程与主程序一起运行,但它们不共享任何变量,而是使用 glib 的异步队列仅在一个方向上传递消息。

同样的代码使用 glib 的GHashTable来存储键/值对。当信号代码被注释出系统时,哈希表似乎运行良好。但是,当启用它时,存在一个奇怪的竞争条件,即对g_hash_table_lookup的调用实际上返回 NULL(意味着没有用于查找它的键的条目),而该条目确实存在(是的,我通过打印带有 g_hash_table_foreach 的键/值对的整个列表来确保)。为什么大多数时候会发生这种情况?GLib的哈希表实现有问题吗?有时查找调用会成功。

这是一个非常特殊的情况,如果它没有意义,我可以进一步澄清,但我希望我做错了什么,以便实际上可以解决这个问题。

详细信息:不在信号处理程序范围内但访问g_hash_table变量的代码段被信号阻止调用包围,因此信号处理程序在进程最初访问这些变量时也不会访问这些变量。

通常,信号处理程序只能设置标志并进行系统调用

碰巧的是,ISO C 中对信号处理程序可以做什么有严格的限制,大多数库入口点和大多数 API 甚至不是远程 100% 多线程安全的,其中大约 0.0% 是信号处理程序安全的。也就是说,绝对禁止从信号处理程序调用几乎任何内容。

特别是,对于 GHashTable,g_hash_table_ref()g_hash_table_unref() 是唯一线程安全的 API 元素,它们都不是信号处理程序安全的。实际上,ISO-C 只允许信号处理程序修改用 volatile sig_atomic_t 声明的对象,并且只能调用几个库例程。

我们中的一些人认为线程系统本质上是危险的,实际上是微妙错误的放射源。开始担心的一个好地方是线程问题。(请注意,信号处理程序本身要糟糕得多。没有人认为 API 在那里是安全的......

最新更新