简体   繁体   English

STL队列的线程安全性

[英]Thread safety for STL queue

I am using a queue to communicate between threads. 我正在使用队列来在线程之间进行通信。 I have one reader and multiple writer threads. 我有一个读者和多个编写器线程。 My question is do I need to lock the queue every time when I use push/front/pop from the queue for the reader? 我的问题是,每当我从队列中使用push / front / pop进行读取时,我是否需要锁定队列? Can I do something like the following: 我可以做以下事情:

//reader threads
getLock();
get the number of elements from the queue
releaseLock();

int i = 0;
while( i < numOfElements){
    queue.front();
    queue.pop();
    i++
}

The idea is that I want to reduce the granularity of the locked code and since the writer thread would only write to the back of the queue and there is only a single reader thread. 我的想法是,我想减少锁定代码的粒度,因为编写器线程只会写入队列的后面,并且只有一个读取器线程。 As long as I get the number of elements, then I could get the elements from the queue OR do I need to enclose the front() and pop() in the lock as well? 只要我获得了元素的数量,那么我就可以从队列中获取元素,或者我是否需要在锁中包含front()pop()

As others have already mentioned, standard containers are not required to guarantee thread safety so what you're asking for cannot be implemented portably. 正如其他人已经提到的那样,标准容器不需要保证线程安全,因此您所要求的内容无法实现。 You can reduce the time your reader thread is locking the writers out by using 2 queues and a queue pointer that indicates the queue that is currently in use by the writers. 您可以通过使用2个队列和一个指示编写器当前正在使用的队列的队列指针来缩短读取器线程锁定写入器的时间。

Each writer would: 每位作家都会:

  • Acquire lock 获取锁定
  • Push element(s) into the queue currently pointed to by the queue pointer 将元素推入队列指针当前指向的队列中
  • Release lock 解锁

The reader can then do the following: 然后读者可以执行以下操作:

  • Acquire lock 获取锁定
  • Switch queue pointer to point to the second queue 切换队列指针指向第二个队列
  • Release lock 解锁
  • Process elements from the first queue 处理第一个队列中的元素

Any type that doesn't explicitly state its thread-safety guarantees should always be controlled by a mutex. 任何未明确声明其线程安全保证的类型应始终由互斥锁控制。 That said, your implementation's stdlib may allow some variation of this — but you can't know for all implementations of std::queue. 也就是说,你的实现的stdlib可能允许一些变化 - 但你不能知道std :: queue的所有实现。

As std::queue wraps another container (it's a container adapter), you need to look at the underlying container, which defaults to deque. 当std :: queue包装另一个容器(它是容器适配器)时,您需要查看底层容器,默认为deque。

You may find it easier, better, or more portable to write your own container adapter that makes the guarantees you need. 您可能会发现编写自己的容器适配器更容易,更好或更便携,从而提供所需的保证。 I don't know of anything that does this exactly for a queue in Boost. 我不知道为Boost中的队列做了什么。

I haven't looked at C++0x enough to know if it has any solution for this out-of-the-box, but that could be another option. 我没有看过C ++ 0x足以知道它是否有任何开箱即用的解决方案,但这可能是另一种选择。

This is absolutely implementation-dependent. 这绝对是依赖于实现的。 The C++ standard makes no mention about threads or thread safety, so whether or not this will work depends on how your implementation handles queue elements. C ++标准没有提及线程或线程安全性,因此这是否有效取决于您的实现如何处理队列元素。

In your case, the reader is actually popping the queue, which is considered a write operation. 在您的情况下,读者实际上弹出队列,这被认为是写操作。 I doubt any of the common implementations actually guarantee thread-safety in this case, when multiple threads simultaneously write to a container. 我怀疑当多个线程同时写入容器时,任何常见的实现实际上都保证了线程安全性。 At least VC++ does not: 至少VC ++没有:

For reads to the same object, the object is thread safe for reading when no writers on other threads. 对于对同一对象的读取,当没有其他线程上的编写器时,该对象对于读取是线程安全的。

For writes to the same object, the object is thread safe for writing from one thread when no readers on other threads. 对于对同一对象的写入,当没有其他线程上的读取器时,该对象对于从一个线程写入是线程安全的。

Your hunch is correct: Even though you cannot count on STD queue to be thread safe, a queue should be thread safe by design . 你的预感是正确的:即使你不能指望STD队列是线程安全的,一个队列应该是线程安全的设计

A nice explanation of why that is the case and a standard implementation of thread safe, lock free queues in C++ is given by van Dooren van Dooren给出了一个很好的解释,为什么会这样,并且在C ++中使用线程安全,无锁队列的标准实现

Sometimes you can resolve a lot of concurrency headache by avoiding sharing state or resources among threads. 有时,您可以通过避免在线程之间共享状态或资源来解决许多并发问题。 If you have multiple threads that access a container concurrently in order to push in their work then try to have them work on dedicated containers. 如果您有多个线程同时访问容器以便推进其工作,那么尝试让它们在专用容器上工作。 At specific points you then collect the containers' elements onto the central container in a non-concurrent manner. 然后,在特定点,您将以非并发方式将容器的元素收集到中央容器中。

If you can avoid sharing state or resources among threads then you have no problem running threads concurrently. 如果您可以避免在线程之间共享状态或资源,那么您可以同时运行线程没有问题。 Threads then need not worry about each other, because they are completely isolated and bear no effect whatsoever on each other. 然后线程不必互相担心,因为它们完全是孤立的,对彼此没有任何影响。

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

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