版权声明:所有的博客都是个人笔记,交流可以留言或者加QQ:2630492017 https://blog.csdn.net/qq_35976351/article/details/84190505
线程安全的栈
该线程安全栈的作用是,允许多个线程对栈进行操作,不必再栈上进行加锁,而是栈本身内部封装了锁的机制。操作的本身不是并行化的,因为不可能同时对栈既添加数据,又取出数据;其真正的意义是多个线程访问时,避免上述不安全的情况发生。
#include <exception>
#include <stack>
#include <mutex>
#include <utility>
#include <memory>
// 自定义异常
struct empty_stack: std::exception {
const char* what() const throw() {};
};
template<typename T>
class threadsafe_stack {
public:
threadsafe_stack() {}
threadsafe_stack(const threadsafe_stack& other) {
std::lock_guard<std::mutex> lock(m);
data = other.data;
}
// 不允许直接复制
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
// 元素入栈操作
void push(T new_value) {
std::lock_guard<std::mutex> lock(m);
data.push(std::move(new_value));
}
// 元素出栈,返回指针
std::shared_ptr<T> pop() {
std::lock_guard<std::mutex> lock(m);
if(data.empty()) {
throw empty_stack();
}
std::shared_ptr<T>const res(std::make_shared<T>(std::move(data.top())));
data.pop();
return res;
}
// 元素出栈,传递引用的方式
void pop(T &value) {
std::lock_guard<std::mutex> lock(m);
if(data.empty()) {
throw empty_stack();
}
value = std::move(data.top());
data.pop();
}
// 判断栈是否是空的
bool empty()const {
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
private:
std::stack<T>data;
mutable std::mutex m;
};
补充说明:
mutable
关键字:该关键字与const
相对应,在const
函数中,原则上不允许修改成员变量,但是如果声明为mutable
,那么可以进行修改。what()
:该函数是继承标准异常是需要重写的函数,参考这篇博客
线程安全的队列
普通版本的线程安全队列:
#include <mutex>
#include <queue>
#include <condition_variable>
template<typename T>
class threadsafe_queue {
public:
threadsafe_queue() {}
threadsafe_queue(const threadsafe_queue& other) {
std::lock_guard<std::mutex> lock(mtx);
data_queue = other.data_queue;
}
threadsafe_queue& operator=(const threadsafe_queue&) = delete;
void push(T new_value) {
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(std::move(new_value));
data_cond.notify_one();
}
void wait_and_pop(T& value) {
std::unique_lock<std::mutex>lock(mtx);
data_cond.wait(lock, [this] {return !data_queue.empty();});
data_queue.pop();
}
std::shared_ptr<T>wait_and_pop() {
std::unique_lock<std::mutex>lock(mtx);
data_cond.wait(lock, [this] {return !data_queue.empty();});
data_queue.pop();
}
bool try_pop(T& value) {
std::lock_guard<std::mutex>lock(mtx);
if (data_queue.empty()) {
return std::shared_ptr<T>();
}
std::shared_ptr<T>res(std::make_shared<T>(std::move(data_queue.front())));
data_queue.pop();
return res;
}
bool empty() const {
std::lock_guard<std::mutex>lock(mtx);
return data_queue.empty();
}
private:
mutable std::mutex mtx;
std::queue<T> data_queue;
std::condition_variable data_cond;
};