互斥锁和死锁
Mutexes and deadlocks
本文关键字:死锁 更新时间:2023-10-16
在这里问了一个关于互斥锁的问题之后,我被警告要注意死锁。
我下面列出的例子是避免死锁的合理方法吗?
class Foo
{
public:
Foo();
void Thread();
int GetWidgetProperty();
int GetGadgetProperty();
private:
Widget widget_;
Gadget gadget_;
VDK::MutexID widgetLock;
VDK::MutexID gadgetLock;
};
Foo::Foo()
: widget_(42)
, gadget_(widget_)
{
widgetLock = VDK::CreateMutex();
gadgetLock = VDK::CreateMutex();
}
void Foo::Thread()
{
while(1)
{
VDK::AcquireMutex(widgetLock);
// Use widget
VDK::ReleaseMutex(widgetLock);
VDK::AcquireMutex(widgetLock);
VDK::AcquireMutex(gadgetLock);
// use gadget
VDK::ReleaseMutex(widgetLock);
VDK::ReleaseMutex(gadgetLock);
}
}
int Foo::GetWidgetProperty()
{
VDK::AcquireMutex(widgetLock);
return widget_.GetProp();
VDK::ReleaseMutex(widgetLock);
}
int Foo::GetGadgetProperty()
{
VDK::AcquireMutex(widgetLock);
VDK::AcquireMutex(gadgetLock);
return gadget.GetProp();
VDK::ReleaseMutex(widgetLock);
VDK::ReleaseMutex(gadgetLock);
}
由于调用GetGadgetProperty可能导致使用小部件,我猜我们还需要在这里使用锁来保护我们的自我。我的问题是,我要求和释放它们的顺序是否正确?
您的代码有明显的死锁。不能在return语句后释放互斥锁。更重要的是,最好以相反的顺序解锁。正确的代码应该是这样的:
int Foo::GetWidgetProperty()
{
VDK::AcquireMutex(widgetLock);
int ret = widget_.GetProp();
VDK::ReleaseMutex(widgetLock);
return ret;
}
int Foo::GetGadgetProperty()
{
VDK::AcquireMutex(widgetLock);
VDK::AcquireMutex(gadgetLock);
int ret = gadget.GetProp();
VDK::ReleaseMutex(gadgetLock);
VDK::ReleaseMutex(widgetLock);
return ret;
}
一个更好的方法是依靠RAII来为你做这项工作。
我邀请你阅读std::lock_guard。基本原则是通过声明一个对象来获取互斥锁。互斥锁在生命周期结束时自动释放。
现在,您可以对需要以这种方式锁定互斥锁的代码区域使用块作用域:
{
std::lock_guard lockWidget{widgetMutex};//Acquire widget mutex
std::lock_guard lockGadget{gadgetMutex};//Acquire gadget mutex
//do stuff with widget/gadget
//...
//As the lock_guards go out of scope in the reverse order of
//declaration, the mutexes are released
}
当然,这适用于标准库的互斥体,因此您必须适应您的使用。
这将防止错误,例如试图在返回语句之后释放互斥锁,这显然是永远不会发生的,或者面对在实际释放互斥锁之前可能发生的异常。
相关文章:
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- 用C++中的std::condition_variable将线程置于死锁中会有风险吗
- 使用 std::async 时死锁,将来作为成员
- 如何调试读写器锁的死锁?
- 为什么在Visual Studio 2013上的std::this_thread::sleep_for上死锁
- localtime() 函数正在调用 ___lll_lock_wait_private(),这会使线程陷入死锁
- 如何重现 Boost 进程文档提示的死锁?
- 多线程Windows GUI应用程序中的死锁
- 为什么printf会导致与future.get的死锁,而cout则不会?
- C++中具有阻塞队列和障碍的死锁
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 避免并发等待对象中的死锁
- 在VC++中从DLLMAIN内部调用D3D的CREATEDEVICE时,它会创建一个死锁(loaderlock?)。有没有办法克服这个问题?最终目标内
- 当用2个螺纹锁定时,将recursive_mutex死锁
- 程序在 C++11 中使用条件变量进入死锁
- 一个线程提升的死锁
- 单个生产者/多个消费者死锁
- 当被调用方法使用调用方已锁定的同一锁时,如何避免死锁
- 如何实现无保留和等待以防止死锁