代码之家  ›  专栏  ›  技术社区  ›  NuSkooler

在生产者消费者代码中使用wait()来增强条件死锁

  •  4
  • NuSkooler  · 技术社区  · 14 年前

    我已经使用Boost线程和条件实现了一个基本的线程生产者使用者(线程1=生产者,线程2=消费者)。我陷进去了 WAIT() 无限期地,相当频繁。我真的看不出这里有什么问题。下面是一些伪代码:

    // main class
    class Main {
    public:
      void AddToQueue(...someData...)
      {
        boost::mutex::scoped_lock lock(m_mutex);
        m_queue.push_back(new QueueItem(...someData...));
        m_cond.notify_one(); 
      }
    
      void RemoveQueuedItem(...someCond...)
      {
        // i'm wondering if this could cause the trouble?
        boost::mutex::scoped_lock lock(m_mutex);
        // erase a item matching condition (some code not shown,
        // but should be fairly self-explanatory -- IsMatch()
        // simply looks at a flag of QueueItem
        m_queue.erase(std::remove_if(m_queue.being(), m_queue.end(),
          boost::bind(&Main::IsMatch, this, _1, someCond), m_queue.end());
      }
    
      friend void WorkerThread(Main* m);
    private:      
      boost::ptr_deque<QueueItem> m_queue;
      boost::mutex m_mutex;
      boost::condition m_cond;
    };
    
    // worker thread
    void WorkerThread(Main* m)
    {
      typedef boost::ptr_deque<QueueItem>::auto_type RelType;
      RelType queueItem;
    
      while(!shutDown) {
        { // begin mutex scope
          boost::mutex::scoped_lock lock(m->m_mutex);
          while(m->m_queue.empty()) {
            m->m_cond.wait(lock); // <- stuck here forever quite often!
          }
          queueItem = m->m_queue->pop_front(); // pop & take ptr ownership
        } // end mutex scope
    
        // ... do stuff with queueItem
        // ...
        // ... queueItem is deleted when it leaves scope & we loop around
      }
    }
    

    一些附加信息:

    • 使用Boost v1.44
    • 这个问题在Linux和Android中发生;我还不确定它是否在Windows中发生。

    有什么想法吗?

    更新 : 我 相信 我孤立了这个问题。一旦确认,我会进一步更新,希望明天。

    更新2 : 事实证明,上述代码中没有问题。我依赖于addtoqueue()的底层API—当处理工作线程中的数据并将其返回到API时,它有一个循环错误,在该错误中它将再次调用addtoqueue()…现在固定了;-)

    2 回复  |  直到 14 年前
        1
  •  2
  •   Community CDub    8 年前

    我最近做了类似的事情,尽管我使用STL队列。看看您是否可以从我的实现中挑选出来。AS wilx 说,你需要在这种情况下等待。我的实现对队列中的元素有最大限制,我使用它来等待互斥/保护被释放。

    我最初在Windows上做这项工作时考虑到了使用互斥体或关键部分的能力,因此可以删除和使用模板参数。 boost::mutex 如果它为您简化了它,就可以直接使用。

    #include <queue>
    #include "Message.h"
    #include <boost/thread/locks.hpp>
    #include <boost/thread/condition.hpp>
    
    template <typename T> class Queue :  private boost::noncopyable
    {
    public:
      // constructor binds the condition object to the Q mutex
      Queue(T & mutex, size_t max_size) :  m_max_size(max_size), m_mutex(mutex){}
    
      // writes messages to end of Q 
      void put(const Message & msg)
      {
        // Lock mutex to ensure exclusive access to Q
        boost::unique_lock<T> guard(m_mutex);
    
        // while Q is full, sleep waiting until something is taken off of it
        while (m_queue.size() == m_max_size)
        {
          cond.wait(guard);
        }
    
        // ok, room on the queue. 
        // Add the message to the queue
        m_queue.push(msg);
    
        // Indicate so data can be ready from Q
        cond.notify_one();
      }
    
      // Read message from front of Q. Message is removed from the Q
      Message get(void)
      {
        // Lock mutex to ensure exclusive access to Q
        boost::unique_lock<T> guard(m_mutex);
    
        // If Q is empty, sleep waiting for something to be put onto it
        while (m_queue.empty())
        {
          cond.wait(guard);
        }
    
        // Q not empty anymore, read the value
        Message msg = m_queue.front();
    
        // Remove it from the queue
        m_queue.pop();
    
        // Signal so more data can be added to Q
        cond.notify_one();
    
        return msg;
      }
    
      size_t max_size(void) const
      {
        return m_max_size;
      }
    
    
    private:
      const size_t m_max_size;
      T & m_mutex;
      std::queue<Message> m_queue;
      boost::condition_variable_any cond;
    };
    

    这样,您就可以在生产者/消费者之间共享队列。示例用法

    boost::mutex mutex;
    
    Queue<boost::mutex> q(mutex, 100);
    
    boost::thread_group threads;
    
    threads.create_thread(Producer<boost::mutex>(q));
    threads.create_thread(Consumer<boost::mutex>(q));
    
    threads.join_all();
    

    生产商/消费者定义如下

    template <typename T> class Producer
    {
    public:
       // Queue passed in
       explicit Producer(Queue<T> &q) :  m_queue(q) {}
    
       void operator()()
       {
       }
    }
    
        2
  •  0
  •   Vinzenz    14 年前
    m->m_cond.wait(); // <- stuck here forever quite often!
    

    应该是:

    m->m_cond.wait( lock ); 
    

    你死了,锁上了你的课,因为你仍然需要互斥,但你在等待。其他所有方法都希望访问相同的互斥体,并等待永远不会释放互斥体的工作人员。

    推荐文章