当生产者消费者数目较多时,用锁实现的线程安全容器锁竞争激烈,上下文切换严重带来较大的性能开销。无所容器实现的关键是为容器的每个槽位设置状态,拿到期望状态的线程通过CAS将状态修改,其他线程因拿不到期望状态二锁死在循环里。
1、无锁队列
/**
* 1. 不分配内存只调用构造函数写法,使用()位置的内存存放对象
* char arr[N];
* new (arr) T;
* 等价于=>
* T* pt = static_cast<T*>(arr);
* pt->T();
* 2. 调用析构函数
* pt->~T();
**/
#pragma once
#include <atomic>
template <typename T>
class LockFreeQueue {
private:
/* 每个元素的状态 空(已弹出) -> 正在入队 -> 入队完成 -> 正在弹出 -> 弹出完成(空)*/
enum Status {
EMPTY = 0,
PUSHING = 1,
PUSHED = 2,
POPING = 3
};
std::atomic<Status>* _state_buf; //用于标记每个元素状态
T* _data_buf; //元素数组
size_t _size; //数组大小
std::atomic<size_t> _head; //队列头,读指针
std::atomic<size_t> _tail; //队列尾,写指针
public:
LockFreeQueue(size_t size) : _size(size), _head(0), _tail(0) {
_data_buf = new T[size];
_state_buf = new std::atomic<Status>[size];
for (int i = 0; i < size; ++i) {
_state_buf[i].store(Status::EMPTY);
}
}
~LockFreeQueue() {
size_t head = _head.load();
size_t tail = _tail.load();
while (head != tail) {
_data_buf[head].~T();
head = (head + 1) % _size;
}
delete[] _data_buf;
delete[] _state_buf;
}
//头尾位置相同时表示队列为空
bool empty() const {
return _head.load() == _tail.load();
}
//尾指针下一个位置为头指针表示队列满
bool full() const {
return _tail.load() + 1 == _head.load();
}
/**
* @brief: 入队。队列满时添加失败返回false
*/
template <typename ...Args>
bool emplace(Args... args) {
//当入栈过程中被其他线程插入时,tail next位置的状态不再是EMPTY
size_t tail = 0;
size_t next = 0;
auto state = Status::EMPTY;
do {
tail = _tail.load();
next = (tail + 1) % _size;
if (next == _head.load()) {//队列满则返回
return false;
}
} while (!_state_buf[tail].compare_exchange_strong(state, Status::PUSHING));
//拿到state槽位的线程正常添加,其他线程会以自旋锁的方式卡在循环里,
//直到上面线程添加完成
new (&_data_buf[tail]) T(std::forward<Args>(args)...);
//更新状态和索引,这行应该不会失败,因为其他生产者都卡在上面循环里
_state_buf[tail].store(Status::PUSHED);
_tail.store(next);
return true;
}
bool pop(T& data) {
//当出栈过程被其他线程出栈,head位置不再是pushed
size_t head = 0;
auto state = Status::PUSHED;
do {
head = _head.load();
if (head == _tail.load()) {//队列空则返回
return false;
}
} while (!_state_buf[head].compare_exchange_strong(state, Status::POPING));
data = std::move(_data_buf[head]);
_data_buf[head].~T();
_state_buf[head].store(Status::EMPTY);
_head.compare_exchange_strong(head, (head + 1) % _size);
return true;
}
};
元素类型为int型时
class LockFreeIntQueue{
private:
enum State {
EMPTY = 0,
PUSHING = 1,
PUSHED = 2,
POPING = 3
};
std::atomic<State>* _states;
int * _data_arr;
size_t _size;
std::atomic<size_t> _head;
std::atomic<size_t> _tail;
public:
LockFreeIntQueue(int size) : _size(size), _head(0), _tail(0) {
_data_arr = new int[size];
_states = new std::atomic<State>[size];
for (int i = 0; i < size; ++i) {
_states[i].store(State::EMPTY);
}
}
~LockFreeIntQueue() {
delete[] _data_arr;
delete[] _states;
}
bool push(int val) {
size_t tail = 0;
State state = State::EMPTY;
do {
tail = _tail.load();
if ((tail + 1) % _size == _head.load()) {
return false;
}
}
while (!_states[tail].compare_exchange_strong(state, State::PUSHING));
_data_arr[tail] = val;
_states[tail].store(State::PUSHED);
_tail.store((tail + 1) % _size);
return true;
}
bool pop(int& val) {
size_t head = 0;
State state = State::PUSHED;
do {
head = _head.load();
if (head == _tail.load()) {
return false;
}
}
while (!_states[head].compare_exchange_strong(state, State::POPING));
val = _data_arr[head];
_states[head].store(State::EMPTY);
_head.store((head + 1) % _size);
return true;
}
};