gpt4 book ai didi

c++ - 为什么 std::queue 不是线程安全的?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:57:32 32 4
gpt4 key购买 nike

主题说明了这一点。我不明白为什么 std::queue(或一般来说:任何队列)本质上不是线程安全的,当没有像其他数据结构那样涉及迭代器时。

根据一般规律

  • 至少有一个线程正在写入...
  • 另一个线程正在读取共享资源

我应该在以下示例代码中遇到冲突:

#include "stdafx.h"
#include <queue>
#include <thread>
#include <iostream>

struct response
{
static int & getCount()
{
static int theCount = 0;
return theCount;
}

int id;
};


std::queue<response> queue;

// generate 100 response objects and push them into the queue
void produce()
{
for (int i = 0; i < 100; i++)
{
response r;
r.id = response::getCount()++;
queue.push(r);
std::cout << "produced: " << r.id << std::endl;
}
}

// get the 100 first responses from the queue
void consume()
{
int consumedCounter = 0;
for (;;)
{
if (!queue.empty())
{
std::cout << "consumed: " << queue.front().id << std::endl;
queue.pop();
consumedCounter++;
}

if (consumedCounter == 100)
break;
}
}

int _tmain(int argc, _TCHAR* argv[])
{

std::thread t1(produce);
std::thread t2(consume);

t1.join();
t2.join();

return 0;
}

一切似乎都运行良好:- 没有违反完整性/数据损坏- 消费者获取元素的顺序是正确的(0<1<2<3<4...),当然是产品的顺序。和缺点。打印是随机的,因为不涉及信号。

最佳答案

假设您检查 !queue.empty(),进入下一个 block ,然后在访问 queue.first() 之前,另一个线程将删除 (pop)唯一的元素,因此您查询一个空队列。

像下面这样使用同步队列

#pragma once

#include <queue>
#include <mutex>
#include <condition_variable>

template <typename T>
class SharedQueue
{
public:
SharedQueue();
~SharedQueue();

T& front();
void pop_front();

void push_back(const T& item);
void push_back(T&& item);

int size();
bool empty();

private:
std::deque<T> queue_;
std::mutex mutex_;
std::condition_variable cond_;
};

template <typename T>
SharedQueue<T>::SharedQueue(){}

template <typename T>
SharedQueue<T>::~SharedQueue(){}

template <typename T>
T& SharedQueue<T>::front()
{
std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
return queue_.front();
}

template <typename T>
void SharedQueue<T>::pop_front()
{
std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
queue_.pop_front();
}

template <typename T>
void SharedQueue<T>::push_back(const T& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push_back(item);
mlock.unlock(); // unlock before notificiation to minimize mutex con
cond_.notify_one(); // notify one waiting thread

}

template <typename T>
void SharedQueue<T>::push_back(T&& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push_back(std::move(item));
mlock.unlock(); // unlock before notificiation to minimize mutex con
cond_.notify_one(); // notify one waiting thread

}

template <typename T>
int SharedQueue<T>::size()
{
std::unique_lock<std::mutex> mlock(mutex_);
int size = queue_.size();
mlock.unlock();
return size;
}

front() 的调用会一直等待,直到它有一个元素并锁定底层队列,这样一次只有一个线程可以访问它。

关于c++ - 为什么 std::queue 不是线程安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36762248/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com