对象的互斥包装

文章介绍了一个Lockable模板类的设计,用于在多线程环境中确保对象的线程安全。通过使用std::timed_mutex作为锁,Lockable类强制要求在修改对象的非原子数据时,必须通过LockWork方法来加锁执行,降低了出错的可能性。测试示例展示了两个线程修改同一个对象的数据和一个线程计算数据之和,没有出现错误,证明了互斥访问的有效性。
摘要由CSDN通过智能技术生成

当一个对象可能被多个线程修改、读取数据时,需要给相应的数据加锁,尤其是堆上的大块数据。锁的来源应该是来自于共享对象,这样才能保证其内部数据同一时间只被一个线程访问。要修改对象的数据时,可以获取锁的引用来加锁,但是这样容易忽略需要加锁的要求,所以设计了一个类,提供统一的接口来使用互斥量,减少失误。

父类:

/*
继承这个类。当子类对象作为(智能)指针在各个线程传递时,使用 LockWork 调用子类的线程不安全函数。
当需要操作子类中非原子的数据时,可以使用lambda、成员函数、全局函数,传入 LockWork 处理。
*/
template<class T>
class Lockable {
private:
    std::timed_mutex mutex_;

    /*
    std::timed_mutex 本身不可拷贝,为了明显,把Lockable也声明为不可拷贝
    */
    Lockable(const Lockable&) = delete;
    Lockable& operator=(const Lockable&) = delete;
public:

    Lockable() = default;

    /// @brief 当需要操作 T 内部非原子类型数据时,确保通过 LockWork 执行
    /// @tparam F 操作函数类型
    /// @tparam ...Args 参数类型
    /// @param f 操作函数
    /// @param ...args 参数列表
    template <class F, class... Args>
    bool LockWork(F&& f, Args &&... args) {
        std::lock_guard<std::timed_mutex> lck(mutex_);
        auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
        func();
        return true;
    }   
};

实现一个子类:

class Foo:public Lockable<Foo>{
public:
    char data[10];
    ~Foo() {
        std::cout << " ~Foo\n";
    }
    void show(int a,int b,int c) {
        std::cout << "show\n";
    }
};

两个测试函数:


Foo f;
std::atomic<bool> stop = false;
void gfunc(int value) {
    auto set = [&]() {
        for (int i = 0; i < 10; i++) {
            f.data[i] = value;
        }
    };

    while (!stop)
    {
        f.LockWork(set);
        //Sleep(10);
    }
}

void gFunc_cal() {
    auto calcu = [&]() {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            sum += f.data[i];
        }
        if (sum && sum != 10 && sum != 20) {
            printf_s("Error");
        }
        else {
            printf_s("Sum is %d\n",sum);
        }
    };
    while (!stop) {
        f.LockWork(calcu);
    }

}

main 函数:

int main()
{
    std::thread th1(gfunc, 1);
    std::thread th2(gfunc, 2);
    std::thread th3(gFunc_cal);
    system("pause");
    stop = true;
    th1.join();
    th2.join();
    th3.join();
    return 0;
}

测试发现不会输出 Error,证明 th1 和 th2 对 f 的操作是互斥的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值