有一组问题可以使用互斥体本身(不需要附加的东西,如条件变量)来同步线程。
例如,假设我希望一个后台线程执行一些可能很耗时的初始化,然后执行它的主作业,但是主作业不应在我从主线程给出信号之前开始:
std::thread backgroundThread ([]() {
initialize ();
waitForSignalQ ();
doMainJob ();
});
…;
emitSignalQ ();
是的,我知道我可以使用互斥量+布尔变量+条件变量来实现WaitForSignalQ
和EmitSignalQ
。 或者,我可以使用void-returning future+void-returning promaces来达到同样的目的,就像Scott Meyers建议的那样。
但这里更简单的方法似乎只是使用一个互斥体:
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();
但这种做法有效吗? 或者是否存在一些缺陷(例如:OS级互斥锁时间限制,软件分析工具的误报等)?
P。 S.:
•是, 我知道,如果MyMutex
没有解锁(由于BackgroundThreadCantStartItsMainJob.Unlock()
之前的异常或其他原因),会出现问题,但问题不在于此(对于condvar和future方法,如果主线程“忘记”发出信号Q,我们会遇到同样的问题)。
•是的,我知道在实践中,使用信号Q的几种变体(例如“继续到主作业”与“取消”)可能是有意义的,但问题不在于此(以及condvar和future方法,所讨论的方法也允许传递额外的数据)。
长时间锁定互斥锁并没有什么特别的缺点。
如果我没有理解错的话,您有一个线程,它将在互斥体的初始化过程中锁定互斥体。 另一个线程将尝试获取该互斥体(确保另一个线程的init已完成),然后在程序运行时的其余部分获取该互斥体。
那很好。 使用互斥体没有运行时成本。 操作系统不会超时或其他任何事情。 这是一个软件工程的挑战:使它清晰,可读和可理解的人将不得不维护它。 除此之外,体系结构真的取决于你。