无锁定的多个矢量编写器
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<uint8_t>
。
...向量会变成线程安全的吗?
安全访问每个元素是不够的。您特别需要避免任何使迭代器无效的操作(交换、调整大小、插入、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 的读写操作。
【讨论】:
以上是关于无锁定的多个矢量编写器的主要内容,如果未能解决你的问题,请参考以下文章
我们可以用两个或多个无锁容器原子地做一些事情而不锁定两者吗?