使用 std::thread 的 C++ 多线程应用程序在 Windows 上运行良好,但在 Ubuntu 上运行良好
Posted
技术标签:
【中文标题】使用 std::thread 的 C++ 多线程应用程序在 Windows 上运行良好,但在 Ubuntu 上运行良好【英文标题】:C++ multithreaded application using std::thread works fine on Windows but not Ubuntu 【发布时间】:2015-12-11 20:47:42 【问题描述】:我有一个使用 C++ std::thread 库为 Ubuntu 14.04 和 Windows 8.1 编写的稍微简单的多线程应用程序。代码几乎完全相同,只是我使用操作系统各自的库 windows.h 和 unistd.h 来使用 Sleep/sleep 暂停执行一段时间。它们实际上都开始运行,并且 Ubuntu 版本确实会继续运行一小段时间,但随后会挂起。我对 sleep/Sleep 函数使用了正确的参数,因为我知道 Windows 睡眠需要几毫秒,而 Unix 睡眠需要几秒钟。
我已经多次运行代码,在 Ubuntu 上它从来没有超过两分钟,而我在 Windows 上运行了两次 20 分钟,然后多次运行大约 5 分钟,看看我是否只是幸运。这只是与线程库的不兼容还是 sleep 没有做我认为的事情,或者其他什么?存在无限循环是因为这是一个学校项目,预计运行时不会出现死锁或崩溃。
要点是,这是一个经过修改的 4 路停靠站,首先到达的汽车不必减速和停车。我们一次只需要让一辆车通过十字路口,需要 3 秒才能通过,因此睡眠(3000),不必担心转弯。三个线程运行 spawnCars 函数,另外还有四个线程分别监控 N、E、S 和 W 四个方向之一。我希望可以理解为什么我不能发布整个代码以防其他学生绊倒在此之上。除了顶部包含的操作系统相关库之外,这两个函数是唯一代码不同的地方。谢谢。
编辑:由于我刚刚发布了项目的所有代码,如果问题最终成为死锁,我可以要求您只这么说,而不是发布深入的解决方案吗?我是新来的,所以如果这违背了 SO 的精神,那就开枪吧,我会在不阅读细节的情况下尝试弄清楚。
/* function clearIntersection
Makes a car go through the intersection. The sleep comes before the removal from the queue
because my understanding is that the wait condition simulates the go signal for drivers.
It wouldn't make sense for the sensors to tell a car to go if the intersection isn't yet
clear even if the lock here would prevent that.
*/
void clearIntersection(int direction)
lock->lock();
Sleep(3000);
dequeue(direction);
lock->unlock();
/* function atFront(int direction)
Checks whether the car waiting at the intersection from a particular direction
has permission to pass, meaning it is at the front of the list of ALL waiting cars.
This is the waiting condition.
*/
bool isAtFront(int direction)
lock->lock();
bool isAtFront = cardinalDirections[direction].front() == list->front();
lock->unlock();
return isAtFront;
void waitInLine()
unique_lock<mutex> conditionLock(*lock);
waitForTurn->wait(conditionLock);
conditionLock.unlock();
//function broadcast(): Let all waiting threads know they can check whether or not their car can go.
void broadcast()
waitForTurn->notify_all();
;
/* function monitorDirection(intersectionQueue,int,int)
Threads will run this function. There are four threads that run this function
in total, one for each of the cardinal directions. The threads check to see
if the car at the front of the intersectionQueue, which contains the arrival order
of cars regardless of direction, is the car at the front of the queue for the
direction the thread is assigned to monitor. If not, it waits on a condition
variable until it is the case. It then calls the function to clear the intersection.
Broadcast is then used on the condition variable so all drivers will check if they
are allowed to pass, which one will unless there are 0 waiting cars, waiting again if not the case.
*/
void monitorDirection(intersectionQueue *intersection, int direction, int id)
while (true) //Do forever to see if crashes can occur.
//Do nothing if there are no cars coming from this direction.
//Possibly add more condition_variables for each direction?
if (!intersection->empty(direction))
while (!intersection->isAtFront(direction))
intersection->waitInLine();
intersection->clearIntersection(direction);
cout << "A car has gone " << numberToDirection(direction) << endl;
//All cars at the intersection will check the signal to see if it's time to go so broadcast is used.
intersection->broadcast();
【问题讨论】:
我正在使用操作系统各自的库 windows.h 和 unistd.h 来使用 Sleep/sleep 暂停执行一段时间。 为什么?我们现在有std::this_thread::sleep_for
。
可能的死锁?我认为您发布的代码不足以让别人帮忙。
我们需要minimal reproducible example 来帮助您。
离题:random_device
is goofy on windows. 你可能会发现你总是得到相同的随机数。
嗯。在第二次通过这只是部分离题。如果你总是得到相同的数字并且它们恰好是不会暴露你的死锁的数字......
【参考方案1】:
你的罪魁祸首很可能是你的while (!isAtFront(...))
循环。如果在检查和后续调用waitInLine()
之间安排了另一个线程,则队列的状态可能会改变,导致所有消费者线程最终等待。那时没有线程可以向您的condition_variable
发出信号,因此他们将永远等待。
【讨论】:
谢谢,我找到了一个解决方案,虽然我认为它不符合好的设计。由于在等待之前我必须持有锁,所以我可以在最终等待之前再次检查我是否在前面,而不必担心队列状态被修改。如果我仍然不在前面,请继续等待,否则解锁并离开,这意味着我会再次浪费地检查条件以离开循环,但不应该发生死锁。我想到的另一件事是在汽车重生时按喇叭,但我想那会有点多。 执行此操作的正确方法可能涉及将后置条件函数作为参数的std::condition_variable::wait()
变体。
看来我应该更频繁地查看文档。我记得当我第一次看 condition_variable 时读到过,但当时我认为我的(错误)方式还可以。以上是关于使用 std::thread 的 C++ 多线程应用程序在 Windows 上运行良好,但在 Ubuntu 上运行良好的主要内容,如果未能解决你的问题,请参考以下文章
使用 std::thread 的 C++ 多线程应用程序在 Windows 上运行良好,但在 Ubuntu 上运行良好
带有 winsock 和 std::thread 的 C++ 多线程服务器
C++并发与多线程 3_线程传参数详解,detach 注意事项