Open In App

Implement thread-safe queue in C++

Improve
Improve
Like Article
Like
Save
Share
Report

What is a Thread-safe Queue?

A thread-safe queue is a data structure that is designed to provide thread safety for a concurrent environment. 

It is a data structure that allows multiple threads to access the same queue and enqueue and dequeue elements concurrently. The threads do not need to be synchronized, as the internal structure of the queue makes sure that the threads do not interfere with each other. Thus, it provides a safe and efficient way to access shared resources from multiple threads.

Why should we use Thread-safe Queue?

  • Thread-safe queues are commonly used in multi-threaded applications, where multiple threads need to access a shared resource. 
  • By using a thread-safe queue, the threads can safely access the queue without the need for synchronization. 
  • This makes it more efficient and less prone to errors. 
  • Thread-safe queues are also useful for tasks that need to be performed in parallel, as they can be used to distribute tasks among multiple threads.

Implementation:

A thread-safe queue in C++ can be implemented using a mutex along with a standard queue. A mutex is a synchronization object used to protect access to a shared resource, such as a thread-safe queue. The mutex should be locked before pushing or popping elements from the queue and unlocked after the operation is complete. A mutex is used to protect access to the queue, while a condition variable is used to wait for changes to the queue.

  • First, the mutex is used to lock the queue whenever a thread attempts to access it. This ensures that only one thread can access the queue at a time. After the thread has finished accessing the queue, it can unlock the mutex. 
  • Next, a condition variable is used to wait for changes to the queue. When a thread adds an item to the queue, it signals the condition variable to indicate that the queue has changed. This allows threads that are waiting for changes to the queue to be woken up and continue.
  • Finally, when a thread attempts to remove an item from the queue, it must first check if the queue is empty. If it is, it can wait on the condition variable until an item is added to the queue. This ensures that the thread will not attempt to remove an item from an empty queue.

Below is the implementation of the above discussion:

C++




// C++ implementation of the above approach
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
  
// Thread-safe queue
template <typename T>
class TSQueue {
private:
    // Underlying queue
    std::queue<T> m_queue;
  
    // mutex for thread synchronization
    std::mutex m_mutex;
  
    // Condition variable for signaling
    std::condition_variable m_cond;
  
public:
    // Pushes an element to the queue
    void push(T item)
    {
  
        // Acquire lock
        std::unique_lock<std::mutex> lock(m_mutex);
  
        // Add item
        m_queue.push(item);
  
        // Notify one thread that
        // is waiting
        m_cond.notify_one();
    }
  
    // Pops an element off the queue
    T pop()
    {
  
        // acquire lock
        std::unique_lock<std::mutex> lock(m_mutex);
  
        // wait until queue is not empty
        m_cond.wait(lock,
                    [this]() { return !m_queue.empty(); });
  
        // retrieve item
        T item = m_queue.front();
        m_queue.pop();
  
        // return item
        return item;
    }
};
  
// Driver code
int main()
{
    TSQueue<int> q;
  
    // Push some data
    q.push(1);
    q.push(2);
    q.push(3);
  
    // Pop some data
    std::cout << q.pop() << std::endl;
    std::cout << q.pop() << std::endl;
    std::cout << q.pop() << std::endl;
  
    return 0;
}


Output

1
2
3

Time Complexity: Best Case : O(1), Worst Case: O(n)
Auxiliary Space: O(n)



Last Updated : 26 Dec, 2022
Like Article
Save Article
Share your thoughts in the comments
Similar Reads