有一组问题,在这些问题中,mutexes本身(没有附加的东西,比如条件变量)可以用来同步线程。
例如,假设我想让一个后台线程执行一些可能耗时的初始化,然后执行它的主工作,但主工作的启动时间不能早于我从主线程发出信号的时间。
std::thread backgroundThread ([]() {
initialize ();
waitForSignalQ ();
doMainJob ();
});
…;
emitSignalQ ();
是的,我知道我可以用mutex+布尔变量+条件变量来实现: waitForSignalQ
和 emitSignalQ
. 或者,我可以使用void-returning future + void-returning promice来达到同样的目的,就像Scott Meyers建议的那样。
但这里更简单的方法似乎是只使用一个mutex。
std::mutex myMutex;
std::unique_lock <std::mutex> backgroundThreadCantStartItsMainJob (myMutex);
std::thread backgroundThread ([&myMutex]() {
initialize ();
// This line won't return until myMutex is unlocked:
std::lock_quard <std::mutex> (myMutex);
doMainJob ();
});
…;
// This line will unlock myMutex:
backgroundThreadCantStartItsMainJob.unlock();
但这种方法有效吗?还是有一些缺点(例如:操作系统级的mutex锁定时间限制。操作系统级的mutex锁定时间限制,软件分析工具的误报等)?)
P. S.: - 是的,我知道这些问题会出现,如果... myMutex
没有被解锁(由于在 backgroundThreadCantStartItsMainJob.unlock()
或等等),但问题不在于此(如果主线程 "忘记 "发出信号Q,那么condvar和未来的方法也会有同样的问题)。- 是的,我知道在实践中,信号Q的几个变体可能是有意义的(比如 "继续主工作 "与 "取消"),问题不在于此(以及condvar和未来的方法,讨论的方法也允许传递额外的数据)。
长时间锁定一个mutex并没有什么特别的弊端。
如果我理解的没错,你有一个线程会在其init期间锁定一个mutex。另一个线程会尝试获取该mutex(以确保另一个线程的init完成),然后在程序运行的剩余时间内获取该mutex。
这很好。拥有mutex没有任何运行时成本。操作系统不会让它超时或任何东西。这个挑战是一个软件工程的挑战。要让维护它的人清楚,可读,可理解。除此以外,架构真的取决于你。