我正在使用线程向量进行繁重的工作,之后我将它们称为join。有时,一切正常,并且可以按预期加入它们。但是,在某些情况下,我感到不由自主地看起来有些混乱,他们崩溃了,说向量迭代器来自另一个容器。
这是我执行多线程处理的功能。
int FindPath(const int nStartX, const int nStartY,
const int nTargetX, const int nTargetY,
const unsigned char* pMap, const int nMapWidth, const int nMapHeight,
int* pOutBuffer, const int nOutBufferSize)
{
vector<Node> nodes(nMapWidth * nMapHeight);
priority_queue<Node*, vector<Node*>, Compare> queue;
vector<thread> threads;
getNodes(nodes, nStartX, nStartY, nTargetX, nTargetY, pMap, nMapWidth, nMapHeight);
queue.push(&nodes[getCoord(nMapWidth, nStartX, nStartY)]);
for (auto i = 0; i < thread::hardware_concurrency(); ++i)
{
threads.push_back(thread(doWork, ref(queue)));
}
for (auto& worker : threads)
{
worker.join();
}
if (nodes[getCoord(nMapWidth, nTargetX, nTargetY)].prev)
{
vector<int> path;
getPath(path, nodes[getCoord(nMapWidth, nTargetX, nTargetY)]);
for (auto i = 0; i < nOutBufferSize; ++i)
{
if (i >= path.size())
{
break;
}
else
{
pOutBuffer[i] = path[i];
}
}
return path.size();
}
else
{
return -1;
}
}
尤其是这部分是随机发生崩溃的地方。
for (auto& worker : threads)
{
worker.join();
}
void doWork(priority_queue<Node*, vector<Node*>, Compare>& queue)
{
while (true)
{
if (!queue.size())
{
unique_lock<mutex> ml(mtx);
cv.wait_until(ml, chrono::system_clock::now() + 10ms);
if (!queue.size())
{
break;
}
}
else
{
Node* node = queue.top();
queue.pop();
for (auto neighb : node->neighb)
{
if (node->distPrev + neighb.second < neighb.first->distPrev)
{
neighb.first->distPrev = node->distPrev + neighb.second;
neighb.first->prev = node;
queue.push(neighb.first);
cv.notify_one();
}
}
}
}
}
如果有帮助,我正在使用VSS 2019社区版本。
答案 0 :(得分:2)
您需要围绕队列的所有读写进行同步。
这样的事情(出于明显的原因,未经测试):
void doWork(priority_queue<Node*, vector<Node*>, Compare>& queue)
{
while (true)
{
Node* node = nullptr;
{
// Wait for an item to appear, or 10 ms to pass.
unique_lock<mutex> ml(mtx);
if (queue.empty())
{
// If the queue is still empty after 10ms, break out.
if (!cv.wait_for(ml, 10ms, [&queue]() { return !queue.empty(); }))
break;
}
// The queue can't be empty here.
node = queue.top();
queue.pop();
}
// Add neighbours.
for (auto neighb : node->neighb)
{
if (node->distPrev + neighb.second < neighb.first->distPrev)
{
neighb.first->distPrev = node->distPrev + neighb.second;
neighb.first->prev = node;
// Lock while adding to the queue.
unique_lock<mutex> ml(mtx);
queue.push(neighb.first);
cv.notify_one();
}
}
}
}
请注意,“等待十毫秒后队列为空”并不是确定工作已完成的非常可靠的方法。
或分为两个功能:
Node* fetch_next(priority_queue<Node*, vector<Node*>, Compare>& queue)
{
unique_lock<mutex> ml(mtx);
if (queue.empty())
{
if (!cv.wait_for(ml, 10ms, [&queue]() { return !queue.empty(); }))
return nullptr;
}
Node* node = queue.top();
queue.pop();
return node;
}
void doWork(priority_queue<Node*, vector<Node*>, Compare>& queue)
{
while (Node* node = fetch_next(queue))
{
for (auto neighb : node->neighb)
{
if (node->distPrev + neighb.second < neighb.first->distPrev)
{
neighb.first->distPrev = node->distPrev + neighb.second;
neighb.first->prev = node;
unique_lock<mutex> ml(mtx);
queue.push(neighb.first);
cv.notify_one();
}
}
}
}
答案 1 :(得分:0)
我的猜测是:dowork()中的以下代码被多个线程异步执行,因此产生了问题:
if (!queue.size())
在else块中,按以下方式访问队列,再次由多个线程异步访问:
Node* node = queue.top();
queue.pop();
同时保护互斥对象下的上述代码片段可能是一个更好的主意?