我正在使用C ++ 11而且我意识到由于std::vector<bool> someArray
对bools的专门化,对std::vector
的并发写入不是线程安全的。
我试图找出对bool someArray[2048]
的写入是否存在同样的问题:
someArray
中的所有条目最初都设置为 false 。someArray.
中的不同索引处写入实际上,这些线程只将不同的数组条目从 false 设置为 true。 问:读者是否会看到在获取锁定之前发生的对someArray
的所有写入?
谢谢!
答案 0 :(得分:3)
您应该使用std::array<bool, 2048> someArray
,而不是bool someArray[2048];
。如果您使用的是C ++ 11-land,那么您需要尽可能地使代码现代化。
std::array<bool, N>
与std::vector<bool>
的专业方式不同,因此原始安全方面没有任何问题。
至于你的实际问题:
读者是否会看到在获取锁定之前发生的对
someArray
的所有写入?
只有当数组的编写者也与锁相互作用时,或者通过在编写完成时释放它,或者通过更新与锁相关的值,读者然后同步用。如果编写器从不与锁进行交互,那么读取器将检索的数据是未定义的。
你还要记住一件事:虽然多个线程写入同一个数组不是不安全,但只要它们都写入唯一的内存地址< / strong>,通过与缓存的交互,写作可能会显着减慢。例如:
void func_a() {
std::array<bool, 2048> someArray{};
for(int i = 0; i < 8; i++) {
std::thread writer([i, &someArray]{
for(size_t index = i * 256; index < (i+1) * 256; index++)
someArray[index] = true;
//Some kind of synchronization mechanism you need to work out yourself
});
writer.detach();
}
}
void func_b() {
std::array<bool, 2048> someArray{};
for(int i = 0; i < 8; i++) {
std::thread writer([i, &someArray]{
for(size_t index = i; index < 2048; index += 8)
someArray[index] = true;
//Some kind of synchronization mechanism you need to work out yourself
});
writer.detach();
}
}
细节将根据底层硬件而有所不同,但几乎在所有情况下,func_a
将比func_b
快几个数量级,至少对于足够大的数组大小(选择2048作为示例,但它可能无法代表实际的基本性能差异)。两个函数都应该具有相同的结果,但其中一个将比另一个快得多。
答案 1 :(得分:0)
首先,一般的std :: vector不像你想象的那样是线程安全的。保证已经说明here。
解决您的问题:读者可能不在获取锁定后看到所有写入。这是因为写入者可能永远不会执行释放操作,这是在写入和后续读取之间建立发生之前关系所需的。在(非常)简单的术语中:每个获取操作(例如互斥锁)都需要一个释放操作来与之同步。在释放到某个可验证之前完成的每个内存操作对于获取相同变量的任何线程都是可见的。另请参阅Release-Acquire ordering。
答案 2 :(得分:0)
需要注意的一件重要事情是,int32大小的变量(例如bool)上的所有操作(获取和存储)都是原子的(对于x86或x64体系结构都适用)。因此,如果您将数组声明为volatile(必需,因为每个线程可能具有数组的缓存值),则在修改数组时(通过多个线程)不应该有任何问题。