c++ - 使用 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();
}
在这个例子中,两个线程将执行这段代码检查,他们会注意到队列不为空,然后他们将进入 if 条件并且其中一个线程首先取回元素,然后幸运的是,同一个线程将弹出元素。在那之后,线程 2 将取回元素,因为线程 1 弹出元素并且现在队列为空,然后线程 2 返回方法失败并出现异常,因此如果队列条件不为空,则进入线程 2 则失败。所以这个队列不是线程安全的
推荐阅读
- java - 带有自签名证书的 Flutter https
- laravel-5 - 图像源在 AbstractDecoder.php 第 346 行的 AbstractDecoder->init({image path}) 中不可读
- gradle - 如何使用类而不是 gradle 套件显示报告门户启动?
- c++ - 类型名称不允许输出 MIDI 文件值
- scala - 如何在pyspark或scala中将字符串转换为时间数据类型?
- spring-statemachine - 如何在 Spring 状态机中获取下一个状态/事件
- docker - 启动单个 docker-compose 服务而不验证其他服务选项
- java - 在java中用空字符串初始化自定义对象
- javascript - atlaskit编辑器如何实现实时协作?
- paypal - 是否可以将 PayPal 订阅作为礼物延长?