简体   繁体   English

C ++条件变量中的boost Synchronized Queue不会在其他线程上通知等待类方法

[英]boost Synchronized Queue in C++ condition variable doesn't notify waiting class method on other thread

I am trying to implement a synchronized queue with condition variables using the boost threading library much like the example here -> ( ImplementingThreadSafeQueue ). 我正在尝试使用boost线程库实现带有条件变量的同步队列,就像这里的示例 - >( ImplementingThreadSafeQueue )。

Background/Purpose : I am writing a windows service as part of a senior design project. 背景/目的 :我正在编写一个Windows服务作为高级设计项目的一部分。 Throughout the service I would like to have various levels of logging (both to files and to the windows event viewer), also I am using my own "EventTimer" wrapper around the "CreateTimerQueueTimer" function to create timed events, like the service reporting a heartbeat. 在整个服务中,我希望有各种级别的日志记录(包括文件和Windows事件查看器),我也使用自己的“EventTimer”包装器围绕“CreateTimerQueueTimer”函数来创建定时事件,如报告服务心跳。 My idea is to push message objects onto a synchronized queue and have a logger class watching the queue on its own thread, waiting to perform the various logging tasks. 我的想法是将消息对象推送到同步队列,并让记录器类在其自己的线程上观察队列,等待执行各种日志记录任务。 For simplicity I am only testing with strings right now. 为简单起见,我现在只测试字符串。

The Problem : The logger thread runs on a method belonging to the logging class to grab work items from the queue. 问题 :记录器线程在属于日志记录类的方法上运行,以从队列中获取工作项。 If I push stuff onto the queue from outside the class, lets say from an EventTimer thread or even from the MAIN thread, the logger never gets notified of new items in the queue. 如果我从类外部将内容推送到队列中,让我们从EventTimer线程或甚至从MAIN线程中提取,则记录器永远不会收到队列中新项目的通知。 However, if I create two threads belonging to the logger class and use one of those threads to push something onto the queue, the logger will see it and respond. 但是,如果我创建属于logger类的两个线程并使用其中一个线程将某些东西推送到队列中,则记录器将看到它并进行响应。 I would like to have any thread be able to add stuff to the queue and have the logger be notified of new items. 我想让任何线程能够向队列中添加内容并让记录器收到新项目的通知。

My code is below. 我的代码如下。 Any help would be appreciated. 任何帮助,将不胜感激。 Thank you for your time! 感谢您的时间!

Synchronized Queue Code 同步队列代码

#ifndef _SYNCHRONIZED_QUEUE_
#define _SYNCHRONIZED_QUEUE_

// Include Files
#include <boost\noncopyable.hpp>
#include <boost\thread.hpp>
#include <queue>

namespace GSMV
{

///////////////////////////////////////////////////////////////////////////////////////
/// Class: SynchronizedQueue
///
/// @Brief
/// SynchronizedQueue is a thread safe STL Queue wrapper that waits on Dequeue and 
/// notifies a listening thread on Enqueue. It is not copyable.
///////////////////////////////////////////////////////////////////////////////////////
template <typename T>
class SynchronizedQueue : private boost::noncopyable 
{
    public:
    struct Canceled{};

    ///////////////////////////////////////////////////////////////////////////////////////
    /// Function: Constructor
    ///
    /// @Brief
    /// Default constructor for the SynchronizedQueue object.
    ///////////////////////////////////////////////////////////////////////////////////////
    SynchronizedQueue(void)
    {
      // Queue is not canceled to start with
      this->mCanceled = false;       

      // Nobody waiting yet
      this->mWaiting = 0;
    }

    ///////////////////////////////////////////////////////////////////////////////////////
    /// Function: Enqueue
    /// 
    /// @Param const T &item: Item of type T to add to queue. 
    ///
    /// @Brief
    /// Adds an item of type T to the queue notifying via a condition.
    ///////////////////////////////////////////////////////////////////////////////////////
        void Enqueue(const T &item)
        {
      bool enqueued = false;

      // acquire lock on the queue
      boost::unique_lock<boost::mutex> lock(this->mMutex);

      // make sure the queue is not canceled
      if (this->mCanceled)
        throw Canceled();

      // add item to the queue
            this->mQueue.push(item);

      // notify others that queue has a new item
      this->mItemAvailable.notify_one();
        }

    ///////////////////////////////////////////////////////////////////////////////////////
    /// Function: Dequeue
    /// 
    /// @Return
    /// Item of type T from front of queue. 
    ///
    /// @Brief
    /// Returns an item of type T from the queue and deletes the front of the queue. Thread
    /// will wait on an empty queue until it is signaled via Enqueue.
    ///////////////////////////////////////////////////////////////////////////////////////
        T Dequeue(void)
        {
      // acquire lock on the queue
      boost::unique_lock<boost::mutex> lock(this->mMutex);

      // make sure the queue is not canceled
      if (this->mCanceled)
        throw Canceled();

      // one more thread is waiting on this item
      ++this->mWaiting;

      // if the queue is empty, wait until an item is added
      // lock is released inside the wait
      // lock is re-acquired after the wait
            while (this->mQueue.empty())
              this->mItemAvailable.wait(lock);

      // the thread is done waiting now
      --this->mWaiting;

      // retrieve and remove the item from the queue
            T item = this->mQueue.front();
            this->mQueue.pop();

            return item;
      // lock is released
        }

    ///////////////////////////////////////////////////////////////////////////////////////
    /// Function: GetSize
    /// 
    /// @Return
    /// The current size of the queue (number of items in the queue). 
    ///
    /// @Brief
    /// Returns the number of items contained in the queue.
    ///////////////////////////////////////////////////////////////////////////////////////
        int GetSize(void) 
        {
      // acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(this->mMutex);

      // make sure the queue is not canceled
      if (this->mCanceled)
        throw Canceled();

            return this->mQueue.size();
      // lock is released
        }

    ///////////////////////////////////////////////////////////////////////////////////////
    /// Function: IsEmpty
    /// 
    /// @Return
    /// Boolean queue is empty. 
    ///
    /// @Brief
    /// Returns true if queue is empty false otherwise.
    ///////////////////////////////////////////////////////////////////////////////////////
        bool IsEmpty(void)
        {
      // acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(this->mMutex);

      // make sure the queue is not canceled
      if (this->mCanceled)
        throw Canceled();

            return this->mQueue.empty();
      // lock is released
        }

    void Cancel(void)
    {
      // acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(this->mMutex);

      // make sure the queue is not canceled
      if (this->mCanceled)
        throw Canceled();

      this->mCanceled = true;

      // notify all others that queue has a new item
      this->mItemAvailable.notify_all();

      while (0 < this->mWaiting)
        this->mItemAvailable.wait(lock);
    }

    void Reset(void)
    {
      // acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(this->mMutex);

      // reset the canceled arguement
      this->mCanceled = false;
    }

    private:
    bool mCanceled;
    int mWaiting;
        std::queue<T> mQueue; // the STL Queue
        boost::mutex mMutex;  // the mutex object
        boost::condition_variable mItemAvailable; // the signal condition
};

} // Namespace GSMV


#endif /// _SYNCHRONIZED_QUEUE_

Logger Code 记录器代码

#ifndef _LOGGER_H_
#define _LOGGER_H_

#include "SynchronizedQueue.h"
#include <string>
#include <boost\thread.hpp>

namespace GSMV
{

static SynchronizedQueue<std::string> logQ;

class Logger
{
  public:
    Logger(void);
    ~Logger(void);

    bool Start(void);
    bool Stop(void);
    bool IsRunning(void) const;
    void LoggerWorkThread(void);

  private:
    boost::thread* mpLoggerThread;
};

} // Namespace GSMV

#endif
// FILE END - logger.h //



#include "Logger.h"

using namespace GSMV;

Logger::Logger(void)
{
  this->mpLoggerThread = NULL;
}

Logger::~Logger(void)
{
  this->Stop();
}

bool Logger::Start(void)
{
  bool started = this->IsRunning();

  if (!started)
  {
    this->mpLoggerThread = new boost::thread(&Logger::LoggerWorkThread, this);
    started = (NULL != this->mpLoggerThread);
  }

  return started;
}

bool Logger::Stop(void)
{
  bool stopped = !this->IsRunning();

  if (!stopped)
  {
    this->mpLoggerThread->interrupt();
    this->mpLoggerThread->join();

    delete this->mpLoggerThread;
    this->mpLoggerThread = NULL;

    stopped = true;
  }

  return stopped;
}

bool Logger::IsRunning(void) const
{
  return (NULL != this->mpLoggerThread);
}

void Logger::LoggerWorkThread(void)
{
  std::cout << "Enter Logger Work Thread\n" << std::endl;

  while (this->IsRunning())
  {
    std::cout << "LOG: wait for Q..." << std::endl;
    std::string s = logQ.Dequeue();
    std::cout << "LOG: Got item! => " << s << std::endl;

    boost::this_thread::interruption_point();
  }

  std::cout << "Exit Logger Work Thread\n" << std::endl;
}

So using the above code I would create a logger object and call the Start() method. 因此,使用上面的代码,我将创建一个logger对象并调用Start()方法。 Ideally it kicks off a new thread which loops, checking the queue for string items, until the Stop() method is called. 理想情况下,它会启动一个循环的新线程,检查队列中的字符串项,直到调用Stop()方法。 So back in my main function I can push strings onto the queue and the logger should get them, but the logger never gets notified. 所以回到我的main函数中我可以将字符串推送到队列中并且记录器应该得到它们,但是记录器永远不会得到通知。 If it matters the queue is declared in the Logger header file as "static SynchronizedQueue logQ". 如果重要,则队列在Logger头文件中声明为“static SynchronizedQueue logQ”。 Again, I would appreciate any suggestions here. 再次,我将在此感谢任何建议。 Thanks! 谢谢!

您必须在调用条件变量上的notify_onenotify_all之前解锁互斥锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C ++ / BOOST:condition_variable :: wait()/ notify()是否确保等待线程的顺序? - C++/BOOST: Does condition_variable::wait( ) / notify( ) ensure ordering of threads waiting? 在 C++ 中关闭同步队列会阻塞线程 - Shutdown a synchronized queue in C++ blocks the thread 如何在另一个类c ++中通知条件变量 - how to notify condition variable in another class, c++ boost :: thread - 简单示例不起作用(C ++) - boost::thread - Simple example doesn't work (C++) 给一个C ++类foo,里面有一个synchronized方法。 如何保证只有一个线程访问同步方法 - Give a C++ class foo, inside, it has a synchronized method. How to guarantee the synchronized method being accessed by only one thread 有条件等待线程的有序通知(C ++,boost) - Ordered notification of threads waiting on a condition (C++, boost) windows c ++线程等待队列数据推送 - windows c++ thread waiting on queue data-push C++ 在具有同步队列的线程中等待通知 - C++ wait notify in threads with synchronized queues 即使调用了notify_all,工作线程也一直在condition_variable处等待 - worker thread keeps waiting at condition_variable even the notify_all is called dispatch_queue_t 作为 C++ 类中的实例变量 - dispatch_queue_t as instance variable in C++ class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM