在写使用多线程的项目的时候,经常需要给一个变量加锁保护。这里提供一个对需要加锁的变量使用的封装格式。
这里提供普通变量以及std::vector和std::deque两个标准库的封装格式。其他的结构也是相似原理。
使用方式
DoubleBufferData<int> data;
data = 7;
int m = data;
std::cout << m << std::endl;
单独变量封装
#pragma once
#include <atomic>
#include <mutex>
template <class T>
class DoubleBufferData
{
public:
DoubleBufferData():
_data_buffer_updated(false), _has_data(false) {}
DoubleBufferData(const T& data):
_data_buffer_updated(false){
set_data(data);
}
DoubleBufferData& operator=(const T& data){
set_data(data);
return *this;
}
// 隐式转换,但是不支持auto判断,需要显示指明,如上例 int m = data;
operator T() {
return _data_buffer;
}
void set_data(const T& data){
_data_mutex.lock();
_data_buffer = data;
_data_buffer_updated = true;
_has_data = true;
_data_mutex.unlock();
}
const T get_data(){
T data;
_data_mutex.lock();
data = _data_buffer;
_data_buffer_updated = false;
_data_mutex.unlock();
return data;
}
bool is_updated(){
return _data_buffer_updated;
}
bool has_data() {
return _has_data;
}
private:
T _data_buffer;
std::mutex _data_mutex;
std::atomic_bool _data_buffer_updated;
std::atomic_bool _has_data;
};
std::vector 封装
#pragma once
#include <vector>
#include <atomic>
#include <mutex>
template <class T>
class DoubleBufferedVector {
public:
DoubleBufferedVector(int max_size = 10):
data_buffer_updated(false),
max_size(max_size) {
}
void push_data(const T& data) {
std::lock_guard<std::mutex> lg(data_mutex);
if (data_buffer.size() > max_size) {
data_buffer.pop_back();
overflowed = true;
}
data_buffer.push_back(data);
data_buffer_updated = true;
}
void push_data(const std::vector<T>& data) {
std::lock_guard<std::mutex> lg(data_mutex);
for (auto& t : data){
data_buffer.push_back(t);
if (data_buffer.size() > max_size) {
data_buffer.pop_back();
overflowed = true;
}
}
data_buffer_updated = true;
}
const std::vector<T> get_data() {
std::lock_guard<std::mutex> lg(data_mutex);
data.clear();
if (data_buffer_updated) {
data.swap(data_buffer);
data_buffer_updated = false;
overflowed = false;
}
return data;
}
const std::vector<T> peek_data() {
std::vector<T> data;
if (data_buffer_updated) {
data_mutex.lock();
data = data_buffer;
data_mutex.unlock();
}
return data;
}
void clear() {
std::lock_guard<std::mutex> lg(data_mutex);
data_buffer.clear();
overflowed = false;
data_buffer_updated = false;
}
void swap(std::vector<T>& vec_data) {
std::lock_guard<std::mutex> lg(data_mutex);
if (!data_buffer_updated) {
data_buffer.clear();
}
data_buffer.swap(vec_data);
}
bool is_updated() {
return data_buffer_updated;
}
bool is_overflowed() {
return overflowed;
}
private:
std::vector<T> data;
std::vector<T> data_buffer;
std::mutex data_mutex;
std::atomic<bool> data_buffer_updated;
int max_size;
bool overflowed = false;
};
std::deque封装
#pragma once
#include <deque>
#include <atomic>
#include <mutex>
template <class T>
class DoubleBufferedQueue {
public:
DoubleBufferedQueue(int max_size = 10):
data_buffer_updated(false),
max_size(max_size) {
}
void push_data(const T& data) {
data_mutex.lock();
data_buffer.push_back(data);
data_buffer_updated = true;
if (data_buffer.size() > max_size) {
data_buffer.pop_front();
overflowed = true;
}
data_mutex.unlock();
}
void push_data(const std::deque<T>& data) {
data_mutex.lock();
data_buffer.clear();
for (auto& t : data){
data_buffer.push_back(t);
data_buffer_updated = true;
if (data_buffer.size() > max_size) {
data_buffer.pop_front();
overflowed = true;
}
}
data_mutex.unlock();
}
const std::deque<T> get_data() {
if (data_buffer_updated) {
data_mutex.lock();
data.clear();
data.swap(data_buffer);
data_buffer_updated = false;
overflowed = false;
data_mutex.unlock();
}
return data;
}
const std::deque<T> peek_data() {
std::deque<T> data;
if (data_buffer_updated) {
data_mutex.lock();
data = data_buffer;
data_mutex.unlock();
}
return data;
}
void clear() {
data.clear();
data_mutex.lock();
data_buffer.clear();
overflowed = false;
data_buffer_updated = false;
data_mutex.unlock();
}
void swap(std::deque<T>& que_data) {
get_data();
data.swap(que_data);
}
bool is_updated() {
return data_buffer_updated;
}
bool is_overflowed() {
return overflowed;
}
private:
std::deque<T> data;
std::deque<T> data_buffer;
std::mutex data_mutex;
std::atomic<bool> data_buffer_updated;
int max_size;
bool overflowed = false;
};