繁体   English   中英

使用 pthreads 创建线程安全队列是否正确?

[英]is it correct way to create a thread safe queue using pthreads?

最近开始学习多线程,所以有些东西还是不太明白。 我试图写一个线程安全的队列,但我怀疑我是否做对了。 由于我没有注意到我的错误,如果您向我指出错误,我会很高兴。 谢谢你的回复,还有。 我不确定我是否在此代码中正确使用了条件变量。

template<class T>
class SafeQueue {
private:
    std:: queue<T> _data;
    pthread_mutex_t _mutex;
    pthread_cond_t _condition;
public:
    SafeQueue();
    ~SafeQueue();
    void push(const T &x);
    T front();
    T back();
    void pop();
    int size();
    bool empty();
};

template<class T>
SafeQueue<T>::SafeQueue(){
    pthread_mutex_init(&_mutex, NULL);
    pthread_cond_init(&_condition, NULL);
}

template<class T>
SafeQueue<T>::~SafeQueue(){
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_condition);
}

template<class T>
void SafeQueue<T>::push(const T &x){
    pthread_mutex_lock(&_mutex);
    _data.push(x);
    pthread_cond_signal(&_condition);
    pthread_mutex_unlock(&_mutex);
}

template<class T>
T SafeQueue<T>::front(){
    pthread_mutex_lock(&_mutex);
    if(_data.empty() && _data.size() == 0){
        pthread_mutex_unlock(&_mutex);
        throw SafeQueueException("Queue is empty");
    }
    if(_data.empty()){
        pthread_cond_wait(&_condition, &_mutex);
    }
    T temp = _data.front();
    pthread_mutex_unlock(&_mutex);
    return temp;
}

template<class T>
T SafeQueue<T>::back(){
    pthread_mutex_lock(&_mutex);
    if(_data.empty() && _data.size() == 0){
        pthread_mutex_unlock(&_mutex);
        throw SafeQueueException("Queue is empty");
    }
    if(_data.empty()){
        pthread_cond_wait(&_condition, &_mutex);
    }
    T temp = _data.back();
    pthread_mutex_unlock(&_mutex);
    return temp;
}

template<class T>
void SafeQueue<T>::pop(){
    pthread_mutex_lock(&_mutex);
    if(_data.empty() && _data.size() == 0){
        pthread_mutex_unlock(&_mutex);
        throw SafeQueueException("Queue is empty");
    }
    if(_data.empty()){
        pthread_cond_wait(&_condition, &_mutex);
    }
    _data.pop();
    pthread_mutex_unlock(&_mutex);
}

template<class T>
int SafeQueue<T>::size(){
    pthread_mutex_lock(&_mutex);
    int temp = _data.size();
    pthread_mutex_unlock(&_mutex);
    return temp;
}

template<class T>
bool SafeQueue<T>::empty(){
    pthread_mutex_lock(&_mutex);
    bool temp = _data.empty();
    pthread_mutex_unlock(&_mutex);
    return temp;
}

代码中的一些点我不太明白为什么你把_data.empty() && _data.size() == 0这样的东西? 当您只能使用其中一个时。 而且也不需要锁定大小和空方法,因为它们只是读取变量并返回它们,它们不会修改任何东西。

顺便提一句。

确实有些人认为如果他们将互斥锁放在开始和结束操作中是一些数据结构(在你的情况下是队列),那么他们认为它现在是线程安全的,但它不是真的。

例如,假设您的队列有一个元素。

q = 1

然后你有一些这样的代码:

if (!q.empty()) {
  auto element = q.back();
  q.pop();
}

在这个例子中,两个线程将执行这段代码检查,他们会注意到队列不为空,然后他们将在内部 go 条件和一个线程首先取回元素,然后运气好,同一个线程将弹出元素。 在那之后,线程 2 将取回元素,因为线程 1 弹出元素并且现在队列为空,然后线程 2 返回方法失败并出现异常,因此如果队列条件不为空,则进入线程 2 则失败。 所以这个队列不是线程安全的

很高兴看到你正在扩展你的技能。 如果您使用的是 C++,那么 C++11 之后的标准库中有线程。 我建议您改用这些功能。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM