c++11并发编程历程(16):并发设计以及并发设计数据结构的思考
发布日期:2021-05-24 18:35:20 浏览次数:25 分类:精选文章

本文共 849 字,大约阅读时间需要 2 分钟。

并发设计的意义

在最基本的层面,为并发设计数据结构意味着多个线程可以同时使用此数据结构执行相同或不同的操作,而每个线程都试图保持数据结构的一致性。这种设计不仅不会丢失或破坏数据,还能维持所有不变量,并且避免不确定的竞争条件。因此,这种数据结构被称为线程安全。通常,只有在特定的并发存取下,一种数据类型才是安全的。

并发设计不仅仅是为多个线程提供存取数据结构的并发机会。实际上,它更深层次地保护数据。一种互斥元通过明确阻止对它所保护数据进行并发存取来保护数据,这被称为序列化,即多个线程必须线性的而非并发地存取数据。核心思想是:通过最小的保护区域,让尽可能少的操作被序列化,从而最大限度地提高并发潜能。

并发设计数据结构的准则

为并发存取设计数据结构时,需要在保证存取安全ity的同时,允许真正的并发存取。

数据结构线程安全的原理

为了保证线程安全,需要注意以下几点:

  • 在数据结构不变性被破坏时,确保其它线程不会读取或修改已经污染的状态。
  • 避免数据接口固有的竞争现象。重要的是提供完整的操作函数,而不是分解为多个步骤。
  • 考虑异常情况下数据结构如何确保不变性不被破坏。
  • 限制锁的范围,避免使用嵌套锁,以降低死锁的风险。

在考虑这些细节前,先要明确数据结构的使用限制。如果一个函数通过特殊函数使用数据结构,那么其他线程调用哪个函数是安全的?这是一个关键性的问题。大多数构造函数和析构函数需要以独占方式访问数据结构,即需要通过加锁机制保证它们在构造完成前或析构开始后没有被使用。

实现真正的并发

实现真正的并发设计是一个复杂的问题,可以从以下几个角度来探讨:

  • 一个操作的一部分能否在锁外进行?
  • 数据结构的不同部分能否分别由不同的互斥元保护?
  • 所有操作是否需要相同级别的保护?
  • 数据结构的一个小改变能否在不影响操作语义的情况下提升并发性?

这些问题都可以通过一个核心想法来指导:如何在保证所需的序列化的同时,尽可能地实现并发性?也就是说,如何在必须的序列化中使用最小的保护区域,同时保证数据的一致性和不变性。

上一篇:c++11并发编程历程(17):初探基于锁的并发简单数据结构
下一篇:c++11:std::is_same

发表评论

最新留言

不错!
[***.144.177.141]2025年04月30日 00时40分57秒