美文网首页
多线程下int自增线程安全问题

多线程下int自增线程安全问题

作者: 飞翃荷兰人 | 来源:发表于2020-09-20 00:19 被阅读0次

    一 什么是线程安全

    通俗的说,如果在多线程下,每一个线程都能正常的工作,最终产生的结果也是确定的,那么这就是线程安全的。

    常见的保证线程安全的手段

    常见的有两个保证线程安全的手段,一个是加锁,另一个是采用原子操作(在某些特定情况下)。

    一个线程不安全的实例
    int cnt(0);
    void increase(int time) {
        for (int i = 0; i < time; i++) {
            cnt++;
        }
    }
    
    void decrease(int time) {
        for (int i = 0; i < time; i++) {
            cnt--;
        }
    }
    
    int main(int argc, char** argv) {
        std::thread t1(increase, 1000000);
        std::thread t2(decrease, 1000000);
        t1.join();
        t2.join();
        std::cout << "counter:" << cnt << std::endl;
        return 0;
    }
    

    定义一个全局变量cnt,启用两个线程,分别对全局变量进行加操作和减操作,最终结果为:

    counter:-637175
    

    但是结果应该是0才对。

    方法一:采用锁

    在每次自增或者自减操作之前上锁,操作完成或放锁。

    int cnt(0);
    mutex mtx;
    void increase(int time) {
        for (int i = 0; i < time; i++) {
            mtx.lock();
            cnt++;
            mtx.unlock();
        }
    }
    
    void decrease(int time) {
        for (int i = 0; i < time; i++) {
            mtx.lock();
            cnt--;
            mtx.unlock();
        }
    }
    
    int main(int argc, char** argv) {
        std::thread t1(increase, 1000000);
        std::thread t2(decrease, 1000000);
        t1.join();
        t2.join();
        std::cout << "counter:" << cnt << std::endl;
        return 0;
    }
    
    结果:counter:0
    

    执行操作明显延长了很多,加锁有一定的开销。

    方法二:采用原子操作

    原子操作为c++11新增特性,代码如下:

    #include <atomic>
    
    atomic<int> cnt(0);
    
    void increase(int time) {
        for (int i = 0; i < time; i++) {
            cnt++;
        }
    }
    
    void decrease(int time) {
        for (int i = 0; i < time; i++) {
            cnt--;
        }
    }
    
    int main(int argc, char** argv) {
        std::thread t1(increase, 1000000);
        std::thread t2(decrease, 1000000);
        t1.join();
        t2.join();
        std::cout << "counter:" << cnt << std::endl;
        return 0;
    }
    
    counter:0
    

    执行速度很快,原子操作内部是采用了cas操作,消耗较小(compare and set)。其中

    a++
    

    中的++为atomic的重载运算符,如果写成a=a+1,则失去原子性,结果不正确。同时,以下这些运算符都具有原子性:


    image.png

    相关文章

      网友评论

          本文标题:多线程下int自增线程安全问题

          本文链接:https://www.haomeiwen.com/subject/ilquyktx.html