【问题标题】:I can't understand why does my pthread freeze我不明白为什么我的 pthread 冻结
【发布时间】:2021-08-31 05:11:29
【问题描述】:

我试图创建一个线程安全队列,但出了点问题。我不明白为什么我的线程冻结。 预期:1 2 3,但我什么也没得到(一切都冻结了)

我猜问题是在前面 (pop) 和 get (peek) 方法中滥用条件变量,但我找不到我的错误。 你能指出我的错误并解释错误是什么吗?

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();
    bool peek(T &x);
    bool get(T &x);
};

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_mutex_unlock(&_mutex);
}

template<class T>
T SafeQueue<T>::front(){
    pthread_mutex_lock(&_mutex);
    T temp;
    while(!get(temp)){
        pthread_cond_wait(&_condition, &_mutex);
    }
    pthread_mutex_unlock(&_mutex);
    return temp;
}

template<class T>
bool SafeQueue<T>::get(T &x){
    bool result = false;
    pthread_mutex_lock(&_mutex);
    if(!_data.empty()){
        result = true;
        x = _data.front();
        pthread_cond_signal(&_condition);
    }
    pthread_mutex_unlock(&_mutex);
    return result;
}

template<class T>
void SafeQueue<T>::pop(){
    pthread_mutex_lock(&_mutex);
    T temp;
    while(!peek(temp)){
        pthread_cond_wait(&_condition, &_mutex);
    }
    pthread_mutex_unlock(&_mutex);
}

template<class T>
bool SafeQueue<T>::peek(T &x){
    bool result = false;
    pthread_mutex_lock(&_mutex);
    if(!_data.empty()){
        result = true;
        x = _data.front();
        _data.pop();
        pthread_cond_signal(&_condition);
    }
    pthread_mutex_unlock(&_mutex);
    return result;
}

main.cpp

int main(){
    SafeQueue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);
    cout << q.front() << endl; q.pop();
    cout << q.front() << endl; q.pop();
    cout << q.front() << endl; q.pop();

    return 0;
}

【问题讨论】:

  • 你能用冻结的线程显示代码吗?
  • @Enkidu Edit 您的问题可在需要时添加其他信息。不要在 cmets 中这样做。你应该发一个minimal reproducible example
  • @463035818_is_not_a_number 在问题中添加了它
  • 你得到了什么输出,你期望什么输出?
  • 如何也将其添加到问题中?请阅读minimal reproducible example。问题应包含了解问题到底是什么并重现问题所必需的所有内容

标签: c++ multithreading pthreads


【解决方案1】:

这是你的front

template<class T>
T SafeQueue<T>::front(){
    pthread_mutex_lock(&_mutex);
    T temp;
    while(!get(temp)){
        pthread_cond_wait(&_condition, &_mutex);
    }
    pthread_mutex_unlock(&_mutex);
    return temp;
}

它锁定互斥体,做一些事情,释放互斥体。作为“一些东西”的一部分,它调用get(temp)

您的get 是:

template<class T>
bool SafeQueue<T>::get(T &x){
    bool result = false;
    pthread_mutex_lock(&_mutex);
    if(!_data.empty()){
        result = true;
        x = _data.front();
        pthread_cond_signal(&_condition);
    }
    pthread_mutex_unlock(&_mutex);
    return result;
}

它试图锁定互斥体......

来自docs

如果互斥锁已经被锁定,调用线程将阻塞直到互斥锁可用。

互斥锁永远不会变得可用,因为它被锁定在调用者 (front) 中,只有在get 返回时才会被释放,但get 永远不会返回。

避免这种死锁的一种方法是使用执行实际工作但不使用互斥锁的私有方法。仅在公共方法中锁定互斥锁。然后你只需要确保永远不要从另一个公共方法调用公共方法。或者使用递归互斥锁。

无论如何,我建议您使用std::thread 及其亲属(std::mutex 和其他人)。

【讨论】:

  • 感谢您的帮助!修复后,一切都开始正常工作。
【解决方案2】:

如果我没记错的话,你将互斥锁锁定在 Front() func 中,然后在其中调用 get(temp),它试图再次锁定,这应该是不可能的。

【讨论】:

    猜你喜欢
    • 2016-01-24
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 2020-11-09
    • 2019-06-21
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多