Basic thread-safe stack and queue
We can use C++ synchronization primitives to implement a basic thread-safe stack and queue.
Thread-safe stack
Implementation Notes
#include <iostream>
#include <stack>
#include <algorithm>
#include <thread>
#include <mutex>
#include <memory>
#include <type_traits>
#include <concepts>
#include <shared_mutex>
namespace dev {
template<typename T>
class threadsafe_stack {
public:
using Mutex = std::shared_mutex;
/* Constructors */
// Default constructor
() {}
threadsafe_stack
/*
* This stack is copy-constructible. The copy constructor locks the mutex in the
* source object and then copies the internal stack.
*/
(const threadsafe_stack& other) {
threadsafe_stackstd::unique_lock<Mutex> lck(other.mtx);
m_stack = other.m_stack;
}
// Copy assignment
& operator=(const threadsafe_stack& other) = delete;
threadsafe_stack
~threadsafe_stack() = default;
/*
* pop() is a wrapper over std::stack<T>::top() and std::stack<T>::pop().
* This interface avoids any race conditions that occur between calls to top()
* and pop().
*/
std::shared_ptr<T> pop()
{
std::unique_lock<Mutex> lck(mtx);
if (m_stack.empty())
throw std::exception("Exception - pop() invoked on an empty stack!");
auto result = std::make_shared<T>(std::move(m_stack.top()));
m_stack.pop();
return result;
}
void pop(T& result)
{
std::unique_lock<Mutex> lck(mtx);
if (m_stack.empty())
throw std::exception("Exception - pop() invoked on an empty stack");
= std::move(m_stack.top());
result m_stack.pop();
}
void push(T value)
{
std::unique_lock<Mutex> lck(mtx);
m_stack.push(std::move(value));
}
int size() {
std::shared_lock<Mutex> lck(mtx);
return m_stack.size();
}
/*
* Acquire a std::shared_lock<Mtx> on the mutex, so multiple
* readers can read the stack.
*/
bool empty() {
std::shared_lock<Mutex> lck(mtx);
return m_stack.empty();
}
private:
std::stack<T> m_stack;
;
Mutex mtx};
}
int main()
{
::threadsafe_stack<int> stck;
dev
std::thread writer1(
[&stck]() {
for (int i{ 1 };i <= 1000;++i) {
.push(i);
stck}
}
);
std::thread writer2(
[&stck]() {
for (int i{ 1001 };i <= 2000;++i) {
.push(i);
stck}
}
);
.join();
writer1.join();
writer2
std::cout << "\n" << "Stack size = " << stck.size();
}