对矢量(vector::operator[]和vector:(size))的只读访问是异步安全的

Is read-only access to a vector (vector::operator[] and vector::size()) asynchronous-safe?

本文关键字:vector 安全 异步 读访问 operator size      更新时间:2023-10-16

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

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

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

当抽象机器的处理因接收到信号而中断时都不是

  • volatile std::sig_atomic_t
  • 无锁原子对象(29.4)

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

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

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

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

  • 一个挂起的信号被解除阻塞,并在解除阻塞的呼叫之前发送,它返回

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

来源:开放式集团基础规范第7期IEEE Std 1003.1,2013版,2.4.3

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

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

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

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

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

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

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

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

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

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