微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 同步锁的替代方案

我目前正在开发我自己的小线程图书馆,主要用于学习目的,并且在消息队列的一部分,这将涉及到许多地方的大量同步.以前,我主要使用锁,互斥和条件变量,这些变量都是同一主题的变体,一个只能由一个线程一次使用的部分的锁.

与使用锁相比,是否有任何不同的同步解决方案?我已经在地方阅读了无锁同步,但有些人认为将容器中的锁隐藏为无锁,我不同意.你只是没有自己明确地使用锁.

解决方法

无锁定算法通常涉及使用比较和交换(CAS)或类似的指令来更新内存中的某些值,不仅在原子方面,而且还有条件地和成功的指标.这样你可以编写如下代码
do
{
    read the current value
    calculate the new value
} while(!compare_and_swap(current_value,new_value);

>精确调用语法将随cpu而变化,并且可能涉及汇编语言或提供的系统/编译器提供的包装函数

>使用提供的包装器(如果可用) – 可能会有其他编译器优化或其使用限制为安全行为的问题,否则检查您的文档

重要的是,当有比赛时,比较和交换指令将失败,因为您更新的状态不是您用于计算所需目标状态的状态.这样的指令可以说是“旋转”而不是锁定,因为它们圆形循环,直到吐出成功.

至关重要的是,您现有的线程库可能有一个两阶段的锁定方法,用于互斥锁,读写锁等,包括使用CAS或类似的旋转(即旋转)(如果没有设置,则读取当前值,则cas(current = not set,new = set)}) – 这意味着进行快速更新的其他线程通常不会导致你的线程交换出来等待,并且所有相关耗费的开销与之相关联.第二阶段将告诉操作系统对线程进行排队,直到找到互斥锁为止.这意味着如果您使用互斥体来保护对变量的访问权限,那么您不可能通过实现自己的“互斥体”来保护同一个变量来做得更好.

当您直接使用足够小的变量直接与CAS指令本身进行更新时,锁定自由算法成为自己的算法.而不是…

>获取一个互斥(通过在CAS上旋转,回到较慢的OS队列)
>更新变量
>释放互斥体

…它们通过在CAS上进行旋转来简化(并且做得更快).当然,你可能会发现这项工作是从旧的痛苦中计算出新的价值,重复地推测出来,但是除非有很多的争论,否则你经常不会这么做.

这种仅在内存中更新单个位置的能力具有深远的影响,解决方案可能需要一些创造力.例如,如果您有一个使用无锁算法的容器,则可以决定计算容器中某个元素的潜在变化,但是不能与内存中其他位置更改大小变量进行同步.您可能需要生活没有大小,或者可以使用大小的大小来进行CAS转换,以便稍后增加或减小大小,但任何给定的读取可能会略有错误.您可能需要合并两个与逻辑相关的数据结构(例如空闲列表和元素容器)来共享索引,然后将每个核心字段在每个记录开头处分别放入同一个原子尺寸的字中.这些数据优化可能是非常有侵害性的,有时不会让您获得所需的行为特征. Mutexes等在这方面要容易得多,至少你知道如果需求的演变太过分了,你不需要重写互斥体.也就是说,巧妙地使用无锁方法真的可以满足很多需求,并且产生了非常可喜的性能和可扩展性的改进.

无锁算法的核心(良好)结果是一个线程无法保持互斥体然后发生由调度程序交换出来,以至于其他线程在恢复之前不能工作;而不是使用CAS – 他们可以安全高效地转动,而无需使用操作系统后备选项.

锁定免费算法的东西可以很好地包括更新使用/引用计数器,修改指针以干净地切换指向数据,空闲列表,链接列表,标记使用/未使用的哈希表桶,以及负载平衡.当然还有很多人

正如你所说,只是隐藏在一些API后面使用互斥锁是不锁定的.

原文地址:https://www.jb51.cc/c/113895.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐