线程安全变量封装(C++)

在写使用多线程的项目的时候,经常需要给一个变量加锁保护。这里提供一个对需要加锁的变量使用的封装格式。
这里提供普通变量以及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;
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
hiredis是一个用于C语言的轻量级Redis客户端库。封装hiredis使其线程安全,需要考虑到在多线程环境下,访问Redis服务器可能产生的竞态条件和线程安全问题。 首先,可以通过使用互斥锁(mutex)来实现对hiredis的封装。在每个对Redis的操作函数(如连接、执行命令等)之前,对互斥锁进行加锁操作,以保证同一时间只有一个线程可以对hiredis进行操作。然后,在操作执行完成后,释放互斥锁,使其他线程可以获得对hiredis的访问权限。 其次,为了避免线程之间的竞态条件,可以引入线程安全的数据结构来存储和处理hiredis的请求和响应。例如,可以使用线程安全的队列来存储需要发送给Redis服务器的命令,以及用于存储接收到的响应的缓冲区。在对队列和缓冲区进行访问时,使用互斥锁进行保护,以确保线程之间的安全访问。 此外,还可以考虑使用条件变量(condition variable)来实现异步通知机制。当一个线程向Redis服务器发送了一个命令之后,它可以等待条件变量的通知,以便知道命令已经执行完毕并且可以获取到相应的结果。在命令执行完毕后,可以通过条件变量的通知机制来唤醒等待的线程,并将结果返回给相应的线程。 总之,封装hiredis使其线程安全需要引入互斥锁、线程安全的数据结构以及条件变量等机制,以确保在多线程环境下对Redis服务器的访问能够安全可靠地进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值