zoukankan      html  css  js  c++  java
  • 【C++多线程】共享数据保护

      保护共享数据的最基本的方式,是使用C++标准库提供的互斥量(头文件<mutex>)。当访问共享数据前,使用互斥量将相关数据锁住,再当访问结束后,再将数据解锁。线程库需要保证,当一个线程使用特定互斥量锁住共享数据时,其他的线程想要访问锁住的数据,都必须等到之前那个线程对数据进行解锁后,才能进行访问。这就保证了所有线程能看到共享数据,而不破坏不变量。

      C++中通过实例化 std::mutex 创建互斥量,通过调用成员函数lock()进行上锁,unlock()进行解锁。

     1 #include <iostream>
     2 #include <thread>
     3 #include <mutex>
     4 #include <list>
     5 
     6 using namespace std;
     7 
     8 class A {
     9 public:
    10     void input()
    11     {
    12         for (int i = 0; i < 1000; i++)
    13         {
    14             my_mutex.lock();
    15             cout << "加入数据:" << i << endl;
    16             ilst.push_back(i);
    17             my_mutex.unlock();
    18         }
    19 
    20     }
    21 
    22     void output()
    23     {
    24         for (int i = 0; i < 1000; i++)
    25         {
    26             my_mutex.lock();
    27             if (!ilst.empty())
    28             {
    29                 cout << "读读读读出数据:" << ilst.front() << endl;
    30                 ilst.pop_front();
    31                 my_mutex.unlock();
    32             }
    33             else
    34                 my_mutex.unlock();
    35         }
    36     }
    37 
    38 private:
    39     list<int> ilst;
    40     mutex my_mutex;
    41 };
    42 
    43 int  main()
    44 {
    45     A a;
    46     thread t1(&A::input, &a); //注意此处需要传入的是对象地址,否则数据没办法共享
    47     thread t2(&A::output, &a);
    48     t1.join();
    49     t2.join();
    50     return 0;
    51 }

      C++标准库还为互斥量提供了一个RAII语法的模板类 std::lack_guard<T> ,其会在构造的时候提供已锁的互斥量,并在析构的时候进行解锁,从而保证了一个已锁的互斥量总是会被正确的解锁。

     1 #include <iostream>
     2 #include <thread>
     3 #include <mutex>
     4 #include <list>
     5 
     6 using namespace std;
     7 
     8 class A {
     9 public:
    10     void input()
    11     {
    12         for (int i = 0; i < 1000; i++)
    13         {
    14             lock_guard<mutex> guard(my_mutex);
    15             /*my_mutex.lock();*/
    16             cout << "加入数据:" << i << endl;
    17             ilst.push_back(i);
    18            /* my_mutex.unlock();*/
    19         }
    20 
    21     }
    22 
    23     void output()
    24     {
    25         for (int i = 0; i < 1000; i++)
    26         {
    27             lock_guard<mutex> guard(my_mutex);
    28             /*my_mutex.lock();*/
    29             if (!ilst.empty())
    30             {
    31                 cout << "读读读读出数据:" << ilst.front() << endl;
    32                 ilst.pop_front();
    33                 /*my_mutex.unlock();*/
    34             }
    35             /*else
    36                 my_mutex.unlock();*/
    37         }
    38     }
    39 
    40 private:
    41     list<int> ilst;
    42     mutex my_mutex;
    43 };
    44 
    45 int  main()
    46 {
    47     A a;
    48     thread t1(&A::input, &a); //注意此处需要传入的是对象地址,否则数据没办法共享
    49     thread t2(&A::output, &a);
    50     t1.join();
    51     t2.join();
    52     return 0;
    53 }

      但互斥量自身也有问题。

      当其中一个成员函数返回的是保护数据的指针或引用时,会破坏对数据的保护。具有访问能力的指针或引用可以访问(并可能修改)被保护的数据,而不会被互斥锁限制。所以切勿将受保护数据的指针或引用传递到互斥锁作用域之外,无论是函数返回值,还是存储在外部可见内存,亦或是以参数的形式传递到用户提供的函数中去。

      另外还会造成死锁,或是对数据保护的太多(或太少)的问题

  • 相关阅读:
    javac 命令行使用总结
    电脑右键菜单的编辑(注册表操作)
    C++ —— 类模板的分离式编译
    命令行学习备份
    浏览器老是自动跳出广告垃圾网页
    SQL 事务
    Python中MySQL插入数据
    Python给数字前固定位数加零
    selenium+python3 鼠标事件
    mysql与mongodb命令对比
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13060353.html
Copyright © 2011-2022 走看看