首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何正确解决C++11中的生产者消费者问题

如何正确解决C++11中的生产者消费者问题
EN

Stack Overflow用户
提问于 2017-06-16 06:15:29
回答 2查看 3.5K关注 0票数 2

我正在尝试解决C++11中的生产者和消费者问题,我有一个保存资源的对象,多线程可以添加或消费这些资源。我的问题是,当我试图在该对象上实现“当可用时使用”方法时。请假设插入/删除操作的复杂性微不足道。

稍微解释一下代码中的逻辑。

代码语言:javascript
运行
复制
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;
      }
    }
  }

};

假设以下场景:

-Two线程、T1、T2几乎同时调用addResource和getResource。

-T2锁定互斥,并发现没有更多的资源可用,

所以它必须阻塞,直到有新的资源可用。

所以它解锁互斥锁并设置铃声等待。

-T1运行匹配速度更快。当互斥锁被解锁时,

它立即添加资源,并且在T2设置等待铃之前,

T1已经按了门铃,它不会通知任何人。

-T2无限期地等待铃声响起,但是没有添加更多的资源。

我假设锁定互斥的线程可能是唯一解锁它的线程。因此,如果我尝试在解锁互斥锁之前调用bell.wait,互斥锁永远不会被解锁。

如果可能的话,我想使用没有时间等待或多次检查的解决方案。

那么在C++11中我可以用什么方法来解决这个问题呢?

EN

回答 2

Stack Overflow用户

发布于 2017-06-16 06:24:02

代码语言:javascript
运行
复制
    lock.unlock(); //problem line
    bell.wait(wmux); //waits until addResource rings the bell

是的,这确实是问题所在。

要按照设计正确使用条件变量,在对相关的条件变量执行wait()操作之前,不要对互斥锁执行wait()操作。对条件变量执行wait()操作会在等待期间自动解锁该条件变量,并在线程被notify()-ed后重新获取互斥锁。解锁并等待和通知并锁定后唤醒都是原子操作。

应在互斥锁被锁定时发出所有notify()%s。当互斥锁被完全锁定时,所有的wait()也会被完成。正如我所提到的,由于notify()是原子的,因此所有与互斥锁相关的操作都是原子的,并且是完全顺序的,包括管理互斥锁保护的资源,以及通过条件变量进行线程通知,条件变量现在也受互斥锁保护。

有一些设计模式可以在不使用互斥保护的情况下通知条件变量。但是它们很难正确实现,并且仍然实现线程安全的语义。除了互斥锁保护的所有其他操作外,所有条件变量操作也由互斥锁保护,实现起来要简单得多。

票数 1
EN

Stack Overflow用户

发布于 2017-06-16 09:03:30

需要在互斥锁上向std::condition_variable::wait传递一个锁定的std::unique_lockwait将解锁互斥锁作为其操作的一部分,并将在它返回之前重新锁定它。

使用像std::lock_guardstd::unique_lock这样的锁保护的正常方法是在本地构造它们,并让它们的构造函数锁定你的互斥锁,让它们的析构函数解锁它。

此外,您还可以通过向std::condition_variable::wait提供谓词来避免原始代码中的外部while循环。

代码语言:javascript
运行
复制
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
  }
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44577856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档