是我的等待 - 使用std :: mutex通知机制正确
Is my wait - notify mechanism using std::mutex correct?
我开始使用std :: mutexes停止线程并等待另一个线程恢复它。它是这样的工作:
线程1
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
// Locks it again to pause this thread
myWaitMutex.lock();
线程2
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
但是,我不确定这是否正确,并且在所有平台上都没有问题。如果这不是正确的,那么在C 11中实现此操作的正确方法是什么?
代码的问题
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
.try_lock()
尝试锁定锁并返回 true
,如果成功,,该代码表示" 如果我们将锁定锁定,然后重试,一次又一次地锁定,直到我们失败。我们永远无法"失败",因为我们目前拥有自己正在等待的锁,因此这将是无限的循环。另外,尝试使用呼叫者已经锁定的std::mutex
锁定是UB,因此可以保证这是UB。如果不成功,.try_lock()
将返回false
,并且while
循环将退出。换句话说,这将不是确保静音将被锁定。
确保二线锁定的正确方法是简单的:
myWaitMutex.lock();
这将导致当前螺纹被阻止(无限期(,直到可以锁定锁。
接下来,另一个线程试图解锁mutex 有锁定。
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
这是不起作用的,因为它尚未锁定在std::mutex
上的 .unlock()
。
使用锁
使用Mutex锁时,使用raii所有权 - 包装对象(例如std::lock_guard
(更容易。std::mutex
的使用模式始终是:" 锁 ->在关键部分中做某事 -> unlock "。std::lock_guard
将互斥X锁定在其构造函数中,并将其解锁在其破坏者中。无需担心何时锁定和解锁以及如此低级的东西。
std::mutex m;
{
std::lock_guard<std::mutex> lk{m};
/* We have the lock until we exit scope. */
} // Here 'lk' is destroyed and will release lock.
一个简单的锁可能不是工作的最佳工具
如果您想要的是能够发出线程唤醒的信号,则使用等待并使用 但是,为了进一步使事情复杂化,有一个称为 spurious Wakeups 的东西,这意味着由于未知原因,任何等待线程都可能随时醒来。这是大多数系统上的事实,与线程调度的内部工作有关。另外,由于我们正在处理并发时,我们可能需要检查是否确实需要等待。例如,如果通知线程碰巧在我们开始等待之前通知,那么我们可能会永远等待,除非我们有办法先检查此。 要处理此操作,我们需要添加一个时循环和一个告诉我们何时需要等待以及何时等待的谓词。 还有其他原因是,在循环中等待并使用诸如@david Schwartz的评论中提到的"被盗唤醒"之类的谓词是一个好主意。std::condition_variable
通知结构。std::condition_variable
允许任何呼叫者在不握住任何锁的情况下将信号发送到等待线程。 #include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std::literals;
int main() {
std::mutex m;
std::condition_variable cond;
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
cond.wait(lk); // Will block until 'cond' is notified.
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
cond.notify_all(); // Notify all waiting threads.
t.join(); // Remember to join thread before exit.
}
int main() {
std::mutex m;
std::condition_variable cond;
bool done = false; // Flag for indicating when done waiting.
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
while (!done) { // Wait inside loop to handle spurious wakeups etc.
cond.wait(lk);
}
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
{ // Aquire lock to avoid data race on 'done'.
std::lock_guard<std::mutex> lk{m};
done = true; // Set 'done' to true before notifying.
}
cond.notify_all();
t.join();
}
在我看来,您正在寻找条件变量。最后,应该总是有一种使其通过静音作用的方法,但是条件变量是当前的C 惯用方法来处理"块并等到发生某些情况"的情况。
当固定螺纹锁定的线程时,静音的行为是未定义的。当不固定的线程试图解锁的线程时,静音的行为是不确定的。因此,您的代码可能会在各个平台上完全执行任何操作。
相反,将静音与条件变量和谓词布尔一起使用。在伪代码中:
block:
-
获取静音。
-
虽然谓词是错误的,但在条件变量上阻止。
-
如果您想在此处重新安装武器,请将谓词设置为false。
-
释放静音。
发布:
-
获取静音。
-
将谓词设置为true。
-
信号条件变量。
-
释放静音。
to arenm:
-
获取静音。
-
将谓词设置为false。
-
释放静音。
请检查此代码....
std::mutex m_mutex;
std::condition_variable m_cond_var;
void threadOne(){
std::unique_lock<std::mutex> lck(mtx);
while (!ready){
m_cond_var.wait(lck);
}
m_cond_var.notify_all();
}
void threadTwo(){
std::unique_lock<std::mutex> lck(mtx);
read = true;
m_cond_var.notify_all();
}
希望您能得到解决方案。而且这是非常合适的!
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- 函数如何通知用户它基于函数原型抛出异常?
- 如何在ECS框架中更新组件数据和通知系统
- 当 I2C 值在C++中发生变化时收到通知
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 当可输入框在窗口中处于活动状态时获得通知的任何方法
- std::mutex 如何防止线程修改?
- 是否有必要获取锁并在不需要唤醒线程时通知condition_variable?
- 如何在点击通知时捕获用户的点击操作
- 在通知提升间处理条件变量时未按住锁会导致问题
- 通知条件变量后使用互斥锁
- 如何在不设置值的情况下通知 c++ 未来?
- DRD 报告"conflicting load" std::mutex::lock 上的错误
- 是否需要 mutex() 来安全地同时访问具有 2 个线程的数组的不同元素?
- std::atomic 和 std::mutex 的相对性能
- 使用 ISdigit 通知任何检测到的非法字符
- 如何解决"'mutex' in namespace 'std' does not name a type"?
- Qt:如何通知对象已建立涉及它的信号槽连接
- 提升进程间named_condition_any不通知
- 是我的等待 - 使用std :: mutex通知机制正确