Implement a thread-safe queue
A thread-safe queue is a data structure designed to be used concurrently by multiple threads without data corruption or race conditions. Ensuring thread safety is crucial in multithreaded applications where multiple threads may attempt to access or modify the queue simultaneously. A thread-safe queue typically employs synchronization mechanisms to provide safe and ordered access to its elements.
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
template <typename T>
class ThreadSafeQueue {
private:
std::queue<T> queue_;
mutable std::mutex mutex_;
std::condition_variable condition_;
public:
void enqueue(const T& item) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(item);
condition_.notify_one(); // Notify a waiting consumer
}
T dequeue() {
std::unique_lock<std::mutex> lock(mutex_);
condition_.wait(lock, [this] { return !queue_.empty(); });
T item = queue_.front();
queue_.pop();
return item;
}
};
void producer(ThreadSafeQueue<int>& q, int id) {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
q.enqueue(id * 100 + i);
}
}
void consumer(ThreadSafeQueue<int>& q, int id) {
for (int i = 0; i < 5; ++i) {
int item = q.dequeue();
std::cout << "Consumer " << id << " dequeued: " << item << std::endl;
}
}
int main() {
ThreadSafeQueue<int> tsQueue;
std::thread producer1(producer, std::ref(tsQueue), 1);
std::thread producer2(producer, std::ref(tsQueue), 2);
std::thread consumer1(consumer, std::ref(tsQueue), 1);
std::thread consumer2(consumer, std::ref(tsQueue), 2);
producer1.join();
producer2.join();
consumer1.join();
consumer2.join();
return 0;
}
Output:
Consumer 1 dequeued: Consumer 1002 dequeued: 200
Consumer Consumer 2 dequeued: 1011 dequeued:
201
Consumer 2 dequeued: 102
Consumer 2 dequeued: 202
Consumer 2 dequeued: 103
Consumer 1 dequeued: 203
Consumer 1 dequeued: 104
Consumer 1 dequeued: 204
In this example:
- The
ThreadSafeQueueclass has methodsenqueueto add an item to the queue anddequeueto retrieve an item from the queue. std::mutexis used to guard access to the shared queue, ensuring that only one thread can modify the queue at a time.std::condition_variableis used to coordinate between the producer and consumer threads. The consumer threads wait for the queue to become non-empty before attempting to dequeue.- The
producerfunction adds items to the queue, and theconsumerfunction retrieves items from the queue.