【问题标题】:Is read-only access to a vector (vector::operator[] and vector::size()) asynchronous-safe?对向量(vector::operator[] 和 vector::size())的只读访问是异步安全的吗?
【发布时间】:2014-10-07 17:59:41
【问题描述】:

我的程序需要在SIGINT 的信号处理程序中对vector<string> 的内容执行只读访问。 (替代方法是使用固定长度的 C 字符串的固定大小数组。)该程序设计为在 POSIX 环境中运行。

vector::operator[]vector::size() 是异步安全的(或信号安全的)吗?

【问题讨论】:

    标签: c++ vector posix signal-handling async-safe


    【解决方案1】:

    不,这不安全。 C++11 1.9/6:

    当抽象机的处理因收到信号而中断时,对象的值 都不是

    • 类型为volatile std::sig_atomic_t 也不
    • 无锁原子对象 (29.4)

    在信号处理程序执行期间未指定,并且任何对象的值都不在其中任何一个中 处理程序修改的两个类别变得未定义。

    【讨论】:

    • 哦,好吧。似乎 any 访问向量不是信号安全的。尽管我讨厌使用固定大小的数组,但我想我必须使用一个......
    • @DragonLord 不确定结论 - 标准阅读意味着更多:除非您的数组存储 volatile std::sig_atomic_t 的对象,否则无论如何您都不能使用它。
    • @milleniumbug 是以 null 结尾的 C 字符串好吗?此代码旨在在 POSIX 环境中运行。
    • @DragonLord:你的 C 字符串类型是 volatile std::sig_atomic_t 还是无锁原子对象?没有。 :)
    • @DragonLord “此代码旨在在 POSIX 环境中运行。”在这种情况下,您可以假设 POSIX 允许您做什么。我会尝试添加关于 POSIX 的答案
    【解决方案2】:

    考虑到 C++,Angew 的回答是正确的。既然问题提到了POSIX环境,可以提供更强的保证,这就需要另一个答案,即:

    如果进程是多线程的,或者如果进程是单线程的并且执行信号处理程序不是以下结果:

    • 进程调用abort()raise()kill()pthread_kill()sigqueue()生成未被阻塞的信号

    • 一个挂起的信号在解除阻塞的调用返回之前被解除阻塞并传递

    如果信号处理程序引用除 errno 以外的任何具有静态存储持续时间的对象,而不是通过将值分配给声明为 volatile sig_atomic_t 的对象,或者如果信号处理程序调用在此定义的任何函数,则行为未定义下表中列出的功能之一以外的标准。

    Source: The Open Group Base Specifications Issue 7 IEEE Std 1003.1, 2013 Edition, 2.4.3

    这……仍然是一个非常薄弱的​​保证。据我所知:

    vector::operator[] 不安全。 固定数组不安全。如果数组是非静态的,访问固定数组是安全的。

    为什么? vector::operator[] 没有具体说明它应该如何实现,只有前置条件和后置条件。对数组元素的访问是可能的(如果数组是非静态的),这意味着如果您在发出信号之前创建一个指针(使用vec.data()&vec[0]),那么对向量元素的访问也是安全的,然后通过指针访问元素。

    编辑:最初我错过了这一点,因为我不知道 sigaction 函数 - 使用 signal 您只能在信号处理程序中访问本地数组,但使用 sigaction 您可以提供指向自动和动态数组。不过,在信号处理程序中尽可能少做的建议在这里仍然适用。

    底线:您在信号处理程序中做的太多了。尽量少做。一种方法是分配一个标志(volatile sig_atomic_t 类型),然后返回。代码可以稍后检查标志是否被触发(例如在事件循环中)

    【讨论】:

    • 考虑到明确允许的系统调用列表,不安全的固定数组会很奇怪。
    【解决方案3】:

    我相信,如果您知道访问向量不安全的原因,那么您可以解决它。请注意,访问仍然不能保证安全。但它适用于任何不是死亡站 9000 的东西。

    信号处理程序会中断程序的执行,就像您直接对硬件进行编程时的中断处理程序一样。操作系统只是停止执行您的程序,无论它在哪里。这可能在任何事情的中间。例如,如果您的向量中添加了元素并且它正在更新其大小值,或者将内容复制到一个新的、更长的向量中,则可能会被信号中断。然后您的信号处理程序会尝试从向量中读取,从而导致灾难。

    您可以从信号处理程序访问向量,只要它有效地保持不变。如果你在程序启动时设置了整个东西,然后再也不写了,那么使用它是安全的。请注意,根据标准文件使用并不安全,但实际上是安全的。

    这很像单核 CPU 上的多线程。

    现在,如果您确实需要在程序运行时更新向量,您需要通过在更新向量之前屏蔽信号或禁用处理程序来“锁定”信号处理程序,以确保处理程序不会t 在向量处于不一致状态时运行。

    【讨论】:

    • 好吧,我知道根本原因是一种竞争条件,信号处理程序可能最终在不一致的状态下读取向量。我正在考虑如何使更新原子化,这样就不会发生这种情况......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-01
    • 2021-01-26
    • 2012-02-20
    • 2012-06-05
    • 2012-06-15
    相关资源
    最近更新 更多