C++ STL 队列的线程安全
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4029448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread safety for STL queue
提问by Steveng
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? Can I do something like the following:
我正在使用队列在线程之间进行通信。我有一个读者和多个作者线程。我的问题是,每次我从队列中为读者使用 push/front/pop 时,是否需要锁定队列?我可以执行以下操作吗:
//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()
在锁中?
回答by Praetorian
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
- 获取锁
- 切换队列指针指向第二个队列
- 解除锁定
- 处理第一个队列中的元素
回答by Praetorian
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 的研究还不够深入,不知道它是否有针对这种开箱即用的解决方案,但这可能是另一种选择。
回答by casablanca
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.
对于对同一对象的读取,当其他线程上没有写入者时,该对象是线程安全的。
对于对同一对象的写入,当其他线程上没有读取器时,该对象对于从一个线程写入是线程安全的。
回答by wilhelmtell
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.
如果您可以避免在线程之间共享状态或资源,那么并发运行线程就没有问题。线程就不必担心彼此了,因为它们是完全隔离的,对彼此没有任何影响。
回答by dirkjot
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++ 中线程安全、无锁队列的标准实现