3

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

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

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

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

4

1 回答 1

3

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

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

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

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

于 2012-04-23T04:57:32.827 回答