首页 > 编程语言 > 详细

Effective Modern C++: 多线程与资源互锁 [二]

时间:2020-03-06 21:24:29      阅读:64      评论:0      收藏:0      [点我收藏+]

本文描述用std::atomic实现线程资源互锁

std::atomic用于实现程序里的原子操作,有关原子操作在《C++ Concurrency in Action》中的介绍:

原子操作是一类不可分割的操作,当这样操作在任意线程中进行一半的时候,你是不能查看的;它的状态要不就是完成,要不就是未完成。如果从对象中读取一个值的操作是原子的, 并且对对象的所有修改也都是原子的话,那么加载操作要不就会检索对象初始化的值,要不就将值存在某一次修改中。

另一方面,非原子操作可能会被视为由一个线程完成一半的操作。如果这种是一个存储操作,那么其他线程看到的,可能既不是存储前的值,也可能不是已存储的值。如果非原子操作是一个加载操作,那么它可能会去检索对象的部分成员,或是在另一个线程修改了对象的 值后,对对象进行检索;所以,检索出来的值可能既不是第一个值,也不是第二个值,可能是某种两者结合的值。这就是一个简单的条件竞争,但是这种级别的竞争会构成数据竞争,且会伴有有未定义行为。

 

1. 用std::atomic_flag实现

  std::atomic_flag是最简单的标准原子类型,必须用ATOMIC_FLAG_INIT初始化,支持两种原子操作:

  • test_and_set, 如果atomic_flag对象被设置,则返回true; 如果atomic_flag对象未被设置,则设置之,返回false
  • clear. 清楚atomic_flag对象

  std::atomic_flag可用于多线程之间的同步操作,类似于linux中的信号量。使用atomic_flag可实现mutex.

 1 class Point{
 2 private:
 3     double x;
 4     double y;
 5     mutable std::atomic_flag lock = ATOMIC_FLAG_INIT;
 6 public:
 7     Point(double _x, double _y){
 8         x = _x;
 9         y = _y;
10     }
11     void calculateAndPrintDistance() const{
12         while(lock.test_and_set());
13         double result = pow((x*x + y*y), 0.5);
14         std::cout << result << std::endl;
15         lock.clear();
16     }
17     void setCoordinate(double value){
18         x = value;
19         y = value;
20     }
21 };
22 
23 int main(){
24 
25     const int loop = 100;
26     Point p(0, 0);
27     std::thread threads[loop];
28     for(int i=0; i<loop; i++){
29         p.setCoordinate(i);
30         threads[i] = std::thread(&Point::calculateAndPrintDistance, std::ref(p));
31     }
32     for(int i=0; i<loop; i++){
33         threads[i].join();
34     }
35     return 0;
36 }

2.用std::atomic<T*> 对对象进行封装,std::atomic封装的对象不会进行竞争-冒险。

atomic对象具有两个方法,store和load,分别用于存取数据。

 1 class Point{
 2 private:
 3     double x;
 4     double y;
 5     mutable std::atomic<double> distance;
 6 public:
 7     Point(double _x, double _y){
 8         x = _x;
 9         y = _y;
10     }
11     void calculateDistance() {
12         distance.store(pow((x*x + y*y), 0.5));
13     }
14 
15     void PrintDistance() const{
16         std::cout << distance.load() << std::endl;
17     }
18     void setCoordinate(double value){
19         x = value;
20         y = value;
21     }
22 };
23 
24 int main(){
25 
26     const int loop = 100;
27     Point p(0, 0);
28     std::thread threadsCalc[loop];
29     std::thread threadsPrint[loop];
30     for(int i=0; i<loop; i++){
31         p.setCoordinate(i);
32         threadsCalc[i] = std::thread(&Point::calculateDistance, std::ref(p));
33         threadsPrint[i] = std::thread(&Point::PrintDistance, std::ref(p));
34     }
35     for(int i=0; i<loop; i++){
36         threadsCalc[i].join();
37         threadsPrint[i].join();
38     }
39     return 0;
40 }

 

Effective Modern C++: 多线程与资源互锁 [二]

原文:https://www.cnblogs.com/Asp1rant/p/12430751.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!