无锁定的多个矢量编写器

Posted

技术标签:

【中文标题】无锁定的多个矢量编写器【英文标题】:Multiple vector writers without locking 【发布时间】:2018-01-03 13:33:51 【问题描述】:

我有几个线程写在一个向量中。不同的线程可能会尝试写入相同的字节。没有读取。我可以像示例中那样只使用atomic_fecth_or(),这样向量就会变得线程安全吗?它使用 GCC 编译,没有错误或警告。

    std::vector<std::atomic<uint8_t>> MapVis(1024*1024); 

    void threador()
    
    ...
    std::atomic_fetch_or(&MapVis[i], testor1); 
    

【问题讨论】:

我看不出这种方法行不通的任何原因,但尝试为每个线程提供一个向量实例(包含常规 uint8_t)然后合并结果。 向量有一个固定大小,只有在运行时才知道。 我无法在线程之间划分向量,因为它表示几何位映射(矩形)。线程在不同的区域工作,但在边界,它们可以共享一些字节。 “如果你读取对象或写入不同的对象,从多个线程访问 std::vector 是完全可以的”。正如@VTT 在上面的评论中所建议的那样。 【参考方案1】:

它使用 GCC 编译,没有错误或警告

这没有任何意义,因为编译器不执行那种并发分析。有专门的静态分析工具可以做到这一点并取得不同程度的成功。

我可以只使用atomic_fetch_or ...

你当然可以,而且在每个人的层面上都是安全的std::atomic&lt;uint8_t&gt;

...向量会变成线程安全的吗?

安全访问每个元素是不够的。您特别需要避免任何使迭代器无效的操作(交换、调整大小、插入、push_back 等)。

我不敢说 vector 在这种情况下是线程安全的 - 但你将自己限制在其接口的线程安全子集,因此它可以正常工作。


请注意,正如 VTT 建议的那样,如果可能,最好为每个线程保留一个单独的部分向量。部分是因为它更容易证明正确,部分是因为它避免了内核之间的错误共享。

【讨论】:

【参考方案2】:

是的,这保证是线程安全的,因为 atomic opperations 保证:

与中断、信号、并发进程和线程隔离

因此,当您以原子方式访问MapVis 的元素时,您可以保证写入它的任何其他进程已经完成。并且您的进程在完成写入之前不会被中断。

如果您使用非原子变量,则需要担心的是:

    线程A获取MapVis[i]的值 线程 B 获取 MapVis[i] 的值 线程 A 将 ored 值写入MapVis[i] 线程 B 将 ored 值写入MapVis[i]

如您所见,线程 B 需要等到线程 A 完成写入,否则它只会将线程 A 的更改踩到 MapVis[i]。使用原子变量,读取和写入不能被并发线程中断。这意味着线程 B 不能中断线程 A 的读写操作。

【讨论】:

以上是关于无锁定的多个矢量编写器的主要内容,如果未能解决你的问题,请参考以下文章

C中的读/写器实现

我们可以用两个或多个无锁容器原子地做一些事情而不锁定两者吗?

VDLL矢量型GPS信号跟踪算法,矢量延迟锁定环的matlab仿真

AVX2 矢量化 256 位查找表(32 个无符号字符)

RFID读写器的介绍

急急急!!!如何用java把可编辑的pdf文档转换成不可编辑的pdf文档