Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么std::queue不是线程安全的?_C++_Multithreading_Queue - Fatal编程技术网

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

C++ 为什么std::queue不是线程安全的?,c++,multithreading,queue,C++,Multithreading,Queue,话题就这么说。我不明白为什么std::queue(或者一般来说:anyqueue)本质上不是线程安全的,而不像其他数据结构那样涉及迭代器 按照一般规则 至少有一个线程正在写入 另一个线程正在读取共享资源 我应该在以下示例代码中得到冲突: #include "stdafx.h" #include <queue> #include <thread> #include <iostream> struct response { static int &a

话题就这么说。我不明白为什么std::queue(或者一般来说:anyqueue)本质上不是线程安全的,而不像其他数据结构那样涉及迭代器

按照一般规则

  • 至少有一个线程正在写入
  • 另一个线程正在读取共享资源
我应该在以下示例代码中得到冲突:

#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;
}
#包括“stdafx.h”
#包括
#包括
#包括
结构响应
{
静态int&getCount()
{
静态整数计数=0;
返回计数;
}
int-id;
};
std::队列;
//生成100个响应对象并将它们推入队列
无效产品()
{
对于(int i=0;i<100;i++)
{
响应r;
r、 id=response::getCount()++;
排队推送(r);

std::cout假设您检查
!queue.empty()
,进入下一个块,在访问
queue.first()
之前,另一个线程将删除(弹出)唯一的元素,因此您查询一个空队列

使用如下所示的同步队列

#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;
    }
#pragma一次
#包括
#包括
#包括
模板
类共享队列
{
公众:
SharedQueue();
~SharedQueue();
T&front();
void pop_front();
无效推回(常数和项目);
无效推回(T和项目);
int size();
bool empty();
私人:
std::deque queue_u2;;
std::mutex mutex;
std::条件变量cond;
}; 
模板
SharedQueue::SharedQueue(){}
模板
SharedQueue::~SharedQueue(){}
模板
T&SharedQueue::front()
{
std::unique_lock mlock(互斥锁);
while(queue_u.empty())
{
条件等待(mlock);
}
返回队列前();
}
模板
void SharedQueue::pop_front()
{
std::unique_lock mlock(互斥锁);
while(queue_u.empty())
{
条件等待(mlock);
}
队列u.pop_front();
}     
模板
void SharedQueue::push_back(常量和项目)
{
std::unique_lock mlock(互斥锁);
排队、推回(项目);
mlock.unlock();//在通知之前解锁以最小化互斥锁
cond_u.notify_uone();//通知一个等待的线程
}
模板
void SharedQueue::推回(T&&item)
{
std::unique_lock mlock(互斥锁);
队列向后推(标准::移动(项目));
mlock.unlock();//在通知之前解锁以最小化互斥锁
cond_u.notify_uone();//通知一个等待的线程
}
模板
int SharedQueue::size()
{
std::unique_lock mlock(互斥锁);
int size=队列大小();
mlock.unlock();
返回大小;
}

调用
front()
将等待,直到它拥有一个元素并锁定底层队列,以便一次只能有一个线程访问它。

简单示例:调用
q.empty()
。如果其他东西可以同时添加或删除队列中的元素,那么结果意味着什么?该接口不是为并发使用而设计的。线程安全通常有大量开销,没有线程就完全不用。另外,大多数时候,需要保护的是事务,而不是单个访问首先,即使就其方法而言,
std::queue()
是线程安全的,它如何能够防止在调用
front()
pop()之间向队列添加项目
?如果您运行程序的时间足够长,您至少应该在输出中看到缺少的ID,因为在打印一个元素的ID时,生产者线程会添加另一个元素,然后在打印其ID之前弹出该元素(你会看到刚打印的ID的副本,因为它不会在适当的时间弹出)。如果一切看起来都正常工作,那么我们就不需要定期的软件更新。@Stefano:应该注意的是,那篇文章中的技术依赖于MSVC++如何处理
volatile
变量的非标准细节,甚至MSVC++也可能依赖于所使用的目标和/或编译器选项:我喜欢y我们的实现,我想我会告诉我们这一点。但是在你的解释中,你假设有多个消费者。他只有一个消费者,所以没有其他人会调用empty、first或pop。最坏的情况下,他可能会在
front()之间插入
实现泄漏的抽象。它将引用返回到私有容器中,但不保护元素。如果线程a调用
front()
而线程B调用
pop_front())
事情看起来不太好。引用是一种负担。代码忽略了这一点。你不能将
pop
pop\u-front
分开。线程A和线程B可以先调用
front
,然后两者都调用
pop\u-front
。然后你对一个元素进行了两次处理,一个完全没有。最好在这里回答