ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0.7 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://mezhenskyi.dev/posts/task-queue/ |
| Last Crawled | 2026-03-25 11:45:30 (21 days ago) |
| First Indexed | 2024-10-17 15:43:18 (1 year ago) |
| HTTP Status Code | 200 |
| Meta Title | Thread-safe queue in C++ · Mezhenskyi.dev |
| Meta Description | This article describes a general purpose thread-safe queue implementation in C++. |
| Meta Canonical | null |
| Boilerpipe Text | October 16, 2024
2-minute read
This article describes a general-purpose thread-safe queue. It also provides implementation in C++.
What is a queue?
Link to heading
A regular queue is a fairly straightforward data structure. Its main characteristic is that it uses the
“first in, first out”
principle
(FIFO). That is, the element that gets added first is the first one to be read. Think of it like a pipe: items enter at one end and exit at
the other, in the same order they entered. A simple queue can be implemented using an array or a linked list. Array-based queues use a
contiguous block of memory to store elements. In many cases, they prove more performant than their list-based counterparts. They have good
spatial locality and provide efficient access to the elements stored. Linked list-based queues use nodes connected by pointers, making it more
convenient to add and remove elements dynamically.
However, these basic implementations are not suitable for concurrent environments where multiple threads might access the queue simultaneously.
This is where the concept of a
“thread-safe queue”
becomes crucial.
Thread safety
Link to heading
Imagine a situation where one thread is trying to add an element, while another thread is simultaneously trying to read or remove an element.
Without proper safeguards, this could lead to a race condition, potentially corrupting the queue’s state and causing undefined behavior.
A thread-safe queue addresses these problems by incorporating synchronization mechanisms. More specifically, a typical implementation involves
using a mutex and a condition variable. A mutex protects access to the queue’s state, whereas a condition variable allows consumer threads to
wait efficiently until the queue receives a value to read.
Implementation
Link to heading
Here is a simple C++ implementation:
/* thread_safe_queue.hpp */
#ifndef THREAD_SAFE_QUEUE_HPP
#define THREAD_SAFE_QUEUE_HPP
#include
<condition_variable>
#include
<mutex>
#include
<queue>
template
<
typename
T
>
class
ThreadSafeQueue
{
public
:
ThreadSafeQueue() {}
ThreadSafeQueue
&
operator
=
(ThreadSafeQueue
&
)
=
delete
;
void
push
(T value)
{
std
::
lock_guard
<
std
::
mutex
>
lock(
this
->
mut);
this
->
data.push(value);
this
->
cond.notify_one();
// Notify a waiting consumer.
}
T
pop
()
{
std
::
unique_lock
<
std
::
mutex
>
lock(
this
->
mut);
// Wait until the queue becomes not empty.
this
->
cond.wait(lock, [
this
] {
return
!
this
->
data.empty(); });
T value
=
this
->
data.front();
this
->
data.pop();
return
value;
}
private
:
std
::
queue
<
T
>
data;
std
::
mutex mut;
std
::
condition_variable cond;
};
#endif
// THREAD_SAFE_QUEUE_HPP |
| Markdown | [Mezhenskyi.dev](https://mezhenskyi.dev/)
- [Blog](https://mezhenskyi.dev/posts/)
- [About](https://mezhenskyi.dev/about/)
# [Thread-safe queue in C++](https://mezhenskyi.dev/posts/task-queue/)
October 16, 2024
2-minute read
[c++](https://mezhenskyi.dev/tags/c++/) • [ds](https://mezhenskyi.dev/tags/ds/) • [concurrency](https://mezhenskyi.dev/tags/concurrency/)
This article describes a general-purpose thread-safe queue. It also provides implementation in C++.
## What is a queue? [Link to heading](https://mezhenskyi.dev/posts/task-queue/#what-is-a-queue)
A regular queue is a fairly straightforward data structure. Its main characteristic is that it uses the *“first in, first out”* principle (FIFO). That is, the element that gets added first is the first one to be read. Think of it like a pipe: items enter at one end and exit at the other, in the same order they entered. A simple queue can be implemented using an array or a linked list. Array-based queues use a contiguous block of memory to store elements. In many cases, they prove more performant than their list-based counterparts. They have good spatial locality and provide efficient access to the elements stored. Linked list-based queues use nodes connected by pointers, making it more convenient to add and remove elements dynamically.
However, these basic implementations are not suitable for concurrent environments where multiple threads might access the queue simultaneously. This is where the concept of a *“thread-safe queue”* becomes crucial.
## Thread safety [Link to heading](https://mezhenskyi.dev/posts/task-queue/#thread-safety)
Imagine a situation where one thread is trying to add an element, while another thread is simultaneously trying to read or remove an element. Without proper safeguards, this could lead to a race condition, potentially corrupting the queue’s state and causing undefined behavior.
A thread-safe queue addresses these problems by incorporating synchronization mechanisms. More specifically, a typical implementation involves using a mutex and a condition variable. A mutex protects access to the queue’s state, whereas a condition variable allows consumer threads to wait efficiently until the queue receives a value to read.
## Implementation [Link to heading](https://mezhenskyi.dev/posts/task-queue/#implementation)
Here is a simple C++ implementation:
```
/* thread_safe_queue.hpp */
#ifndef THREAD_SAFE_QUEUE_HPP
#define THREAD_SAFE_QUEUE_HPP
#include <condition_variable>
#include <mutex>
#include <queue>
template <typename T>
class ThreadSafeQueue
{
public:
ThreadSafeQueue() {}
ThreadSafeQueue &operator=(ThreadSafeQueue &) = delete;
void push(T value)
{
std::lock_guard<std::mutex> lock(this->mut);
this->data.push(value);
this->cond.notify_one(); // Notify a waiting consumer.
}
T pop()
{
std::unique_lock<std::mutex> lock(this->mut);
// Wait until the queue becomes not empty.
this->cond.wait(lock, [this] { return !this->data.empty(); });
T value = this->data.front();
this->data.pop();
return value;
}
private:
std::queue<T> data;
std::mutex mut;
std::condition_variable cond;
};
#endif // THREAD_SAFE_QUEUE_HPP
```
© 2025 Nikita Mezhenskyi |
| Readable Markdown | null |
| Shard | 54 (laksa) |
| Root Hash | 12380439019004891054 |
| Unparsed URL | dev,mezhenskyi!/posts/task-queue/ s443 |