C++ 如何正确解决C++;11
我试图在C++11中解决生产者-消费者问题。 我有一个保存资源的对象,多个线程可以 添加或消耗这些资源。我的问题是当我试图实现 该对象上的“可用时使用”方法。 请假定插入/删除操作的复杂性很小 代码中逻辑的一点解释C++ 如何正确解决C++;11,c++,multithreading,c++11,mutex,C++,Multithreading,C++11,Mutex,我试图在C++11中解决生产者-消费者问题。 我有一个保存资源的对象,多个线程可以 添加或消耗这些资源。我的问题是当我试图实现 该对象上的“可用时使用”方法。 请假定插入/删除操作的复杂性很小 代码中逻辑的一点解释 struct ResourceManager{ std::mutex mux; std::unique_lock lock{mux}; std::condition_variable bell; void addResource(/*some Resource*/)
struct ResourceManager{
std::mutex mux;
std::unique_lock lock{mux};
std::condition_variable bell;
void addResource(/*some Resource*/){
lock.lock();
//add resource
lock.unlock();
bell.notify_one(); //notifies waiting consumer threads to consume
}
T getResource(){
while(true){
lock.lock();
if(/*resource is available*/){
//remove resource from the object
lock.unlock();
return resource;
}else{
//new unique lock mutex object wmux creation
lock.unlock(); //problem line
bell.wait(wmux); //waits until addResource rings the bell
continue;
}
}
}
};
假设以下场景:-两个线程T1、T2几乎同时调用addResource和getResource -T2锁定互斥锁,并发现没有更多可用资源,
因此它必须阻止,直到有新的资源可用。
因此,它解锁互斥锁并设置等待的铃声 -T1跑比赛速度更快。当互斥锁解锁时,
它立即添加资源,在T2设置等待铃之前,
T1已经按铃了,没有人知道 -T2无限期地等待铃声响起,但没有添加更多的资源 我假设锁定互斥对象的线程可能是唯一的线程 打开它。如果我试着打电话给bell,在解锁互斥锁之前等待, 互斥锁永远无法解锁 如果可能,我希望使用无时间等待或多次检查解决方案。
在C++11中,我可以用哪种方法解决这个问题
lock.unlock(); //problem line
bell.wait(wmux); //waits until addResource rings the bell
是的,这确实是问题所在
要按照设计正确使用条件变量,请在对其相关条件变量执行wait()
ing操作之前,先解锁互斥锁wait()
ing在等待期间自动解锁条件变量,并在线程被notify()
-ed后重新获取互斥锁。解锁和等待以及在收到通知和锁定后唤醒都是原子操作
当互斥锁锁定时,应发出所有notify()
s。所有wait()
都在互斥锁完全锁定时完成。正如我所提到的,notify()
是原子的,这将导致所有与互斥体相关的操作都是原子的,并且完全按顺序排列,包括管理由互斥体保护的资源,以及通过条件变量(现在也由互斥体保护)进行线程通知
有一些设计模式可以在不使用互斥保护的情况下通知条件变量。但它们更难正确实现,并且仍然实现线程安全语义。除了互斥体保护的所有其他操作之外,让所有条件变量操作也受互斥体保护,实现起来要简单得多。
std::condition\u variable::wait
需要在互斥体上传递一个锁定的std::unique\u lock
wait
将解锁互斥锁作为其操作的一部分,并在返回前重新锁定互斥锁
使用锁防护(如std::lock\u-guard
和std::unique\u-lock
等)的正常方法是在本地构造它们,并让它们的构造函数锁定互斥锁,而它们的析构函数则解锁互斥锁
另外,通过为std::condition\u variable::wait
提供谓词,可以避免原始代码中的外部while
循环
struct ResourceManager {
std::mutex mux;
std::condition_variable bell;
void addResource(T resource)
{
std::lock_guard<std::mutex> lock{mux};
// Add the resource
bell.notify_one();
}
T getResource()
{
std::unique_lock<std::mutex> lock{mux};
bell.wait(lock, [this](){ return resourceIsAvailable(); });
return // the ressource
}
};
struct ResourceManager{
std::互斥多路复用器;
std::条件变量钟;
void addResource(T资源)
{
std::lock_guard lock{mux};
//添加资源
通知某人;
}
T getResource()
{
std::unique_lock lock{mux};
wait(lock,[this](){return resourceisavaailable();});
返回//ressource
}
};
可能与您的问题无关,但请使用锁防护装置,如std::unique_lock
锁定/解锁互斥锁。lock是唯一的锁什么是wmux
?您应该将lock
锁定,然后执行bell。等待(锁定)
,以避免出现竞争条件。@fructedsoul噢,对不起。但这不是如何使用它。通常情况下,您没有成员变量,但有一个局部变量,在离开互斥对象的作用域时只会解锁互斥对象。@fructedsoul:我已经删除了我的解决方案,请您在示例中检查unique_lock和condition_变量的正确用法,这正是您想要做的。谢谢您的回答。因此,如果我理解正确,在addResource中,应该在解锁互斥锁之前调用bell.notify_one()。另外,在getResource中,我应该删除lock.unlock(),并使用bell.wait(lock)代替bell.wait(wmux);我说得对吗?听起来对;当然,这取决于实际的实现细节,因为您只在问题中总结了代码。注意:“lock-std::unique_lock类型的对象,必须由当前线程锁定”。感谢您的时间,您的回答很好地描述了其他人之前已经回答的问题。很遗憾,他删除了他的帖子:S