#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <stack>
#include <stdexcept>
#include <thread>
struct empty_stack : public std::exception {
const char* what() const noexcept { return "Empty stack"; }
};
template <typename T> class threadsafe_stack {
private:
std::stack<T> data;
mutable std::mutex m;
std::condition_variable data_condition;
std::atomic<bool> in_waiting_state{true};
public:
threadsafe_stack() {}
~threadsafe_stack() { stop(); }
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(m);
data = other.data;
}
threadsafe_stack& operator=(const threadsafe_stack& other) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(std::move(new_value));
data_condition.notify_one();
}
//! Updates top value in a stack.
void update_top(T new_value)
{
std::lock_guard<std::mutex> lock(m);
if (!data.empty())
data.pop();
data.push(std::move(new_value));
data_condition.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lock(m);
data_condition.wait(lock, [this] { return !data.empty() || !in_waiting_state; });
if (data.empty())
throw empty_stack();
value = std::move(data.top());
data.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lock(m);
data_condition.wait(lock, [this] { return !data.empty() || !in_waiting_state; });
if (data.empty())
throw empty_stack();
std::shared_ptr<T> const res(std::make_shared<T>(std::move(data.top())));
data.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if (data.empty())
return false;
value = std::move(data.top());
data.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lock(m);
if (data.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res(std::make_shared<T>(std::move(data.top())));
data.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
//! Terminates waiting in wait_and_pop methods.
void stop()
{
std::lock_guard<std::mutex> lock(m);
in_waiting_state = false;
data_condition.notify_all();
}
};
这段代码定义了一个线程安全的栈(threadsafe_stack)类模板,其中包含了多个线程安全的操作。让我们来解释一下这个类的主要功能和每个成员函数的作用:
std::stack<T> data:存储栈元素的私有成员变量。std::mutex m:用于保护对栈数据的访问的互斥量。std::condition_variable data_condition:用于线程间的同步。std::atomic<bool> in_waiting_state{true}:原子布尔值,用于控制等待状态。
成员函数:
push(T new_value):将一个新元素压入栈顶。update_top(T new_value):更新栈顶元素的值。wait_and_pop(T& value):等待并弹出栈顶元素,并将其赋值给 value。std::shared_ptr<T> wait_and_pop():等待并弹出栈顶元素,并返回其指针。try_pop(T& value):尝试弹出栈顶元素,如果成功则将其赋值给 value。std::shared_ptr<T> try_pop():尝试弹出栈顶元素,并返回其指针。empty() const:检查栈是否为空。stop():终止等待状态,通知所有在等待的线程。
这个线程安全的栈类实现了基本的栈操作,并确保在多线程环境下的安全性。通过使用互斥量和条件变量,它可以确保线程安全地对栈进行操作,避免了多线程环境下可能出现的竞态条件和数据竞争问题。
1639

被折叠的 条评论
为什么被折叠?



