【发布时间】:2017-12-19 04:49:45
【问题描述】:
首先我知道一个双端队列上的多个写入器不是很容易处理。但是通过以下算法,我可以保证元素上没有并发访问。该算法将一个双端队列(它非常大,这就是我并行化它的原因)分成块,并且 std::replaces 替换双端队列中的一个值。问题是,在某些情况下,在替换任意值之后,该值似乎仍然存在(顺便说一句:新值与旧值不同的情况并非如此)。是否可能该值未从 cpu 寄存器同步到内存?代码如下:
std::deque<int*> _deque;
...
int threadsCount = 25;
int chunkSize = ceil((float) _deque.size() / (float) threadsCount);
std::vector<std::thread> threads;
for (int threadNo = 0; threadNo < threadsCount; threadNo++) {
std::uint64_t beginIndex = threadNo * chunkSize;
std::uint64_t endIndex = (threadNo + 1) * chunkSize;
if (endIndex > _deque.size()) {
endIndex = _deque.size();
}
std::deque<int*>::iterator beginIterator = _deque.begin() + beginIndex;
std::deque<int*>::iterator endIterator = _deque.begin() + endIndex;
threads.push_back(std::thread([beginIterator, endIterator, elementToReplace, elementNew] () {
std::replace(beginIterator, endIterator, elementToReplace, elementNew);
}));
}
for (int threadNo = 0; threadNo < threadsCount; threadNo++) {
threads[threadNo].join();
}
在该算法之后,有时(非确定性)被替换的 (elementToReplace) 值仍在双端队列中。
【问题讨论】:
-
仅供参考:以
__开头的标识符是保留的,您不应使用它们。 -
begin和end都是非常量成员函数,它们被同时调用,这是一个数据竞争(由deque的接口控制),无论迭代器是否指向到不同的对象 -
@Rakete1111:实际上所有包含
__的标识符都保留给实现用于所有目的。以_开头后跟大写字母的标识符也是如此。 -
@PasserBy 你在技术上当然是正确的,但你能解释一下为什么在这种情况下这可能会导致问题吗?
-
@PasserBy
begin/end需要具有 O(1) 复杂度,因此它们可能只返回一个值。这怎么会导致数据竞争,因为我认为通常只有并发读取是安全的?
标签: c++ memory parallel-processing deque