• atomic原子操作


    C++中对共享数据的存取在并发条件下可能会引起data race的未定义行为,需要限制并发程序以某种特定的顺序执行,有两种方式:1.使用mutex保护共享数据; 2.原子操作

    原子操作:针对原子类型操作要不一步完成,要么不做,不可能出现操作一半被切换CPU,这样防止由于多线程指令交叉执行带来的可能错误。非原子操作下,某个线程可能看见的是一个其它线程操作未完成的数据。

    一、atomic_flag

    std::atomic_flag是一个bool原子类型,有两个状态:set(flag=true) 和 clear(flag=false),必须被ATOMIC_FLAG_INIT初始化,此时flag为clear状态,相当于静态初始化。

    一旦atomic_flag初始化后只有三个操作:test_and_set,clear,析构,均是原子化操作。

    test_and_set检查flag是否被设置,若被设置直接返回true,若没有设置则设置flag为true后再返回false。

    clear()清除flag标志即flag=false。

    不支持拷贝、赋值等操作,这和所有atomic类型一样,因为两个原子类型之间操作不能保证原子化。atomic_flag的可操作性不强导致其应用局限性,还不如atomic<bool>。

    使用atomic_flag作为简单的自旋锁例子:每个线程先将atomic_flag设为true,再设为false

    atomic_flag lock_stream = ATOMIC_FLAG_INIT;//flag处于clear状态,没有被设置过  
    stringstream stream;
    
    void append_number(int x) 
    {
        while (lock_stream.test_and_set()) {}//检查并设置是个原子操作,如以前没有设置过则退出循环,  
                                             //每个线程都等待前面一个线程将lock_stream状态清楚后跳出循环,第一个线程除外,此时lock_stream为clear状态  
        stream << "thread #" << x << '
    ';
        lock_stream.clear();
    }
    
    int main()
    {
        vector<std::thread> threads;
        for (int i = 1; i <= 10; ++i)
            threads.push_back(thread(append_number, i));
        for (auto& th : threads) 
            th.join(); 
        cout << stream.str();
    
        system("pause");
        return 0;
    }

    二、 atomic<T>模板类

    atomic<T>生成一个T类型的原子对象,并提供了系列原子操作函数。其中T是trivially  copyable type,满足:要么全部定义了拷贝/移动/赋值函数,要么全部没定义;没有虚成员;基类或其它任何非static成员都是trivally copyable。典型的内置类型bool、int等属于trivally copyable。再如class triviall{public: int x};也是。

    struct Node 
    { 
        int value; 
        Node* next; 
        Node(int val,Node* p):value(val),next(p){}
    };
    
    atomic<Node*> list_head;
    
    void append(int val) 
    {     // append an element to the list  
        Node* newNode = new Node(val,list_head );
        // next is the same as: list_head = newNode, but in a thread-safe way:  
        while (!list_head.compare_exchange_weak(newNode->next, newNode)) {}
        // (with newNode->next updated accordingly if some other thread just appended another node)  
    }
    
    int main()
    {
        // spawn 10 threads to fill the linked list:  
        vector<thread> threads;
        for (int i = 0; i<10; ++i) 
            threads.push_back(thread(append, i));
        for (auto& th : threads) th.join();
        // print contents:  
        for (Node* it = list_head; it != nullptr; it = it->next)
            cout << ' ' << it->value;
        std::cout << '
    ';
        // cleanup:  
        Node* it; while (it = list_head) { list_head = it->next; delete it; }
    
        system("pause");
        return 0;
    }

    http://blog.csdn.net/liuxuejiang158blog/article/details/17413149

  • 相关阅读:
    MySQL集群常见高可用方案(转)
    upsource使用
    Hystrix 使用
    astah UML 先画图、后编程
    java ThreadLocal 使用
    Java基础 Annotation使用
    LVS+Keepalived+Nginx+Tomcat高可用负载均衡集群配置
    招聘求职学习
    Rotate List 面试题
    vue前台(四点二)
  • 原文地址:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/5957677.html
Copyright © 2020-2023  润新知