item16: 让const成员函数线程安全

// 线程不安全demo
// roots 是const成员函数,那就表示它是一个读操作。在没有同步的情况下,让多个线程执行读操作是安全的
// 但本例没线程安全,线程中的一个或两个尝试修改成员变量rootsAreValid和rootVals,在没有同步的情况下,不同线程读写相同内存,这就是数据竞争
class Polynamial {
public:
    using Rootstype = std::vector<double>;
    Rootstype roots() const {
        if (!rootsAreValid) {
            rootsAreValid = true;
        }
        return rootVals;
    }
private:
    mutable bool rootsAreValid{ false };
    mutable Rootstype rootVals{};
};
// 对于多个线程不安全的变量,最简单的方式是使用mutex(互斥量)
// std::mutex 既不可移动,又不可复制,因此包含他们的类也是不可移动和不可复制的
class Polynamial {
public:
    using Rootstype = std::vector<double>;
    Rootstype roots() const {
        std::lock_guard<std::mutex> g(m);
        if (!rootsAreValid) {
            rootsAreValid = true;
        }
        return rootVals;
    }
private:
    mutable std::mutex m;
    mutable bool rootsAreValid{ false };
    mutable Rootstype rootVals{};
};
// std::atomic 通常是一个开销更小的方法
// std::automic 既不可移动也不可复制,因此包含它们的类也是不可移动和不可复制的
class Point {
public:
    double distance() const noexcept {
        ++callCount;
        return std::sqrt((x*x) + (y*y));
    }
private:
    mutable std::stomic<unsigned> callCount{0};
    double x,y;
};
// 你可能会过度依赖std::automic,尝试使用一对std::automic 变量而不是互斥量
// 此处第一个线程调用magicValue, cacheValue视为false,而第二个线程调用magicValue已将cacheValid视为false,因此线程二执行线程一的计算,线程不安全
class Weight{
public:
    int magicValue() const
    {
        if (cacheValid) return cachedValue;
        else {
            auto val1 = expensiveComputation1();
            auto val2 = expensiveComputation2();
            cachedValue = val1 + val2;              
            cacheValid = true;                      
            return cachedValid;
        }
    }
private:
    mutable std::automic<bool> cacheValid{false};
    mutable std::automic<int> cachedValue;
};
// 对于需要两个以上的变量和内存位置作为一个单元操作的话,就应该使用互斥量 std::mutex
// 可以肯定的是,const成员函数应支持并发执行【理论读】,这就是为什么你应该确保const成员函数是线程安全的
class Widget {
public:
    int magicValue() const
    {
        std::lock_guard<std::mutex> guard(m);   //锁定m
        
        if (cacheValid) return cachedValue;
        else {
            auto val1 = expensiveComputation1();
            auto val2 = expensiveComputation2();
            cachedValue = val1 + val2;
            cacheValid = true;
            return cachedValue;
        }
    }
private:
    mutable std::mutex m;
    mutable int cachedValue;
    mutable bool cacheValid{false};
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值