另一种检查std :: queue事件的方法?

时间:2013-02-04 11:45:53

标签: c++ multithreading events queue std

好吧,我正在尝试处理某种队列。我有一个 IO线程,它专门用于从std :: queue中弹出数据但是问题是我正在使用Sleep()以防止100 %cpu常量检查。 当然还有其他线程会将项添加到std :: queue。

我怎样才能创建事件以便线程处于休眠状态,而当std :: queue非空时,会启动?

IO线程

Sleep(100);
while (!myqueue.empty())
  {
     //process data FIFO
     myqueue.pop(); //pop out and continue
  }

非常感谢,谢谢!哦,这对于c ++ 11或c ++ 03来说无关紧要 - 在Windows上。

3 个答案:

答案 0 :(得分:6)

std::queue 绝对与线程无关。完全没有。它的.empty()成员不是线程安全的(只是可重入的)!这同样适用于其他所有成员。因此,多个线程可以使用不同的队列,但每次只有一个线程可以对每个实例执行任何操作。

C ++ 11或C ++ 03非常重要。因为C ++ 11定义了线程同步原语,而C ++ 03没有,你必须使用OS API。

在C ++ 11中,您会对std::condition_variable感兴趣。

在C ++ 03中,您会对Boost.Thread(大部分与C ++ 11兼容)EventsSemaphores感兴趣。

在任何一种情况下,std::queue::push()std::queue::pop()本身都必须受到互斥的保护。 std::condition_variable甚至会强制您在Windows API中使用std::mutex来使用Critical Section

在Windows上,C ++ 11类仅在Visual Studio 2012和Windows 8中可用。较旧的编译器使用Boost(优点是它可以是可移植的)或本机API。

答案 1 :(得分:1)

你需要一个“条件变量”。每当线程在队列上放置某些东西时,它“通知”等待条件变量的线程。消耗队列中事件的线程会等待条件变量。它是睡着的,直到有人通过条件变量通知它。

Boost有一个很好的实现:http://www.boost.org/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref

您正在使用锁来确保对队列的访问是线程安全的,不是吗?

答案 2 :(得分:0)

我的建议是首先研究如何使用线程安全队列,然后考虑使用boost :: condition信令来提供更多控制。

这是一个如何构建线程安全队列的示例:

#pragma once                                                                              
#include <queue>                                                                       

template<typename T>                                                                       
class thread_safe_queue                                                                    
{                                                                                          
    queue<T>   m_queue;                                                                    
    pthread_mutex_t m_mutex;                                                               
    pthread_cond_t  m_condv;                                                               

    public:                                                                                
    thread_safe_queue() {                                                                  
        pthread_mutex_init(&m_mutex, NULL);                                                
        pthread_cond_init(&m_condv, NULL);                                                 
    }                                                                                      
    ~thread_safe_queue() {                                                                 
        pthread_mutex_destroy(&m_mutex);                                                   
        pthread_cond_destroy(&m_condv);                                                    
    }                                                                                      
    void push(T& item) {                                                                   
        pthread_mutex_lock(&m_mutex);                                                      

        T itemcpy = std::move(item);                                                       
        m_queue.push(std::move(itemcpy));                                                  

        pthread_cond_signal(&m_condv);                                                     
        pthread_mutex_unlock(&m_mutex);                                                    
    }                                                                                      
    T pop() {                                                                              
        pthread_mutex_lock(&m_mutex);                                                      
        while (m_queue.size() == 0) {                                                      
            pthread_cond_wait(&m_condv, &m_mutex);                                         
        }                                                                                  

        T& _item = m_queue.front();                                                        
        T itemcpy = std::move(_item);                                                      

        m_queue.pop();                                                                     
        pthread_mutex_unlock(&m_mutex);                                                    
        return itemcpy;                                                                    
    }                                                                                      
    int size() {                                                                           
        pthread_mutex_lock(&m_mutex);                                                      
        int size = m_queue.size();                                                         
        pthread_mutex_unlock(&m_mutex);                                                    
        return size;                                                                       
    }                                                                                      
};                                                                            

这是你实例化它的方式:

thread_safe_queue<myclass> myqueue;

如果你想使用事件信令,那么请考虑使用boost :: condition - fx。像这样:

#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>

boost::mutex mtxWait;
boost::condition cndSignalQueueHasNewEntry;

bool WaitForQueueSignal(long milliseconds)
{
    boost::mutex::scoped_lock mtxWaitLock(mtxWait);
    boost::posix_time::time_duration wait_duration =  boost::posix_time::milliseconds(milliseconds); // http://www.boost.org/doc/libs/1_34_0/doc/html/date_time/posix_time.html
    boost::system_time const timeout=boost::get_system_time()+wait_duration; // http://www.justsoftwaresolutions.co.uk/threading/condition-variable-spurious-wakes.html
    return cndSignalQueueHasNewEntry.timed_wait(mtxWait,timeout); // wait until signal notify_one or timeout
}

这是您可以发出信号的方式

cndSignalQueueHasNewEntry.notify_one();

这是你可以等待信号的方法

bool bResult = WaitForQueueSignal(10000); // timeout after 10 seconds