自旋锁——代码在循环中“自旋”。

自旋锁(spin lock)是一种非阻塞锁,如果某线程需要获取锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗 CPU 的时间,不停的试图获取锁。

互斥量(mutex)是阻塞锁,当某线程无法获取锁时,该线程会被直接挂起,该线程不再消耗CPU时间,当其他线程释放锁后,操作系统会激活那个被挂起的线程,让其投入运行。

因此,多核 CPU 才能用自旋锁。

其他细节,详看下面代码注释。

#ifndef AMYSPINLOCK_H
#define AMYSPINLOCK_H#include <atomic>// 采用 std::atomic_flag 实现自旋锁互斥,即 TAS 算法(Test And Set)
class AMySpinLock1
{
public:AMySpinLock1() = default;AMySpinLock1(const AMySpinLock1&) = delete;AMySpinLock1& operator=(const AMySpinLock1&) = delete;void lock(){while(flag.test_and_set(std::memory_order_acquire));}void unlock(){flag.clear(std::memory_order_release);}private:// std::atomic_flag 类型的对象必须由宏 ATOMIC_FLAG_INIT 初始化,它把标志初始化为置零状态。std::atomic_flag flag{ATOMIC_FLAG_INIT};
};// 采用 std::atomic<bool> 和 compare_exchange_strong 实现自旋锁互斥,即 CAS 算法(Compare And Swap)
// 比较-交换操作是原子类型的编程基石。
// 使用者给定一个期望值,原子变量将它和自身的值比较,如果相等,就存入另一既定的值,否则,更新期望值所属的变量,向它赋予原子变量的值。
// 比较-交换函数返回布尔类型,如果完成了保存动作(前提是两值相等),则操作成功,函数返回 true;反之操作失败,函数返回 false。
class AMySpinLock2
{
public:AMySpinLock2() = default;AMySpinLock2(const AMySpinLock2&) = delete;AMySpinLock2& operator=(const AMySpinLock2&) = delete;void lock(){// 判断 flag 对象封装的 bool 值是否为期望值(false):// ① 若 bool 值为 false,与期望值相等,说明自旋锁空闲。此时,flag 对象写入 true,返回 true,即上锁成功。// ② 若 bool 值为 true,与期望值不相等,说明自旋锁被锁。此时,while 将一直循环,直到返回 true 为止。bool expected = false;while(false == flag.compare_exchange_strong(expected, true)){// 当 compare_exchange_strong 返回 false 时,// 证明 expected 与 flag 不相等,此时 expected 为false,flag 为 true;// 则将 expected 赋值为 flag 的值,即此时 expected 为 true 了,// 因此要修改为 false 后,才能进入下一次循环。expected = false;}}void unlock(){flag.store(false);}private:// flag 对象所封装的 bool 值为 false 时,说明自旋锁未被线程占有。std::atomic<bool> flag{false};
};#endif // AMYSPINLOCK_H

测试程序如下:

#include <iostream>
#include <thread>
#include "./lock/amyspinlock.h"AMySpinLock1 m;
//AMySpinLock2 m;void testSpinLock()
{static int i = 0, j = 0;for(int k=0; k<1000; ++k){m.lock();++i;std::this_thread::sleep_for(std::chrono::milliseconds(1));++j;if(i != j)printf("[%d] i:%d, j:%d \n", std::this_thread::get_id(), i, j);m.unlock();}
}int main(int argc, char *argv[])
{std::cout << "Test Begin...\n";std::thread t1(testSpinLock);std::thread t2(testSpinLock);if(t1.joinable())t1.join();if(t2.joinable())t2.join();std::cout << "Test End...\n";return 0;
}

【C++】实现自旋锁互斥(TAS 算法和 CAS 算法)相关推荐

  1. 自旋锁/互斥锁/读写锁/递归锁的区别与联系

    自旋锁 互斥锁 读写锁 递归锁 互斥锁(mutexlock): 最常使用于线程同步的锁:标记用来保证在任一时刻,只能有一个线程访问该对象,同一线程多次加锁操作会造成死锁:临界区和互斥量都可用来实现此锁 ...

  2. 进程互斥软件算法(Lamport面包店算法和Eisenberg算法)

    实现进程互斥的软件的结构框架是: Framework Repeat entry section critical section exit section remainder section Unti ...

  3. BF算法和KMP算法

    给定两个字符串S和T,在主串S中查找子串T的过程称为串匹配(string matching,也称模式匹配),T称为模式.这里将介绍处理串匹配问题的两种算法,BF算法和KMP算法. BF算法 (暴力匹配 ...

  4. Algorithm:C++语言实现之字符串相关算法(字符串的循环左移、字符串的全排列、带有同个字符的全排列、串匹配问题的BF算法和KMP算法)

    Algorithm:C++语言实现之字符串相关算法(字符串的循环左移.字符串的全排列.带有同个字符的全排列.串匹配问题的BF算法和KMP算法) 目录 一.字符串的算法 1.字符串的循环左移 2.字符串 ...

  5. 操作系统之存储管理——FIFO算法和LRU算法

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  6. 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。

    目   录 题目: 百度文库-答案: (1) (2) MOOC标准答案: (1) (2) mooc答案-截图: 数据结构(C语言版)-严蔚敏2007 题目: 设字符串S='aabaabaabaac', ...

  7. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  8. 基于Huffman算法和LZ77算法的文件压缩的改进方向

    基于Huffman算法和LZ77算法的文件压缩(八) 到这里已经简单实现基于Huffman算法和LZ77算法的文件压缩, GitHub源码:点我 根据基于Huffman算法和LZ77算法的文件压缩(七 ...

  9. 最短路径Dijkstra算法和Floyd算法整理、

    转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径-Dijkstra算法和Floyd算法 Dijks ...

  10. 用Spark学习FP Tree算法和PrefixSpan算法

    在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法.由于scikit-l ...

最新文章

  1. 如何在Matlab中获取函数参数的数目?
  2. 分配委托、匿名委托、委托
  3. 用Core Temp查看服务器CPU温度
  4. c51语言定义全局变量,全局变量的定义和使用
  5. python爬虫框架--scrapy 基本使用
  6. 测试内存兼容软件,Ryzen内存兼容性测试_内存硬盘行情-中关村在线
  7. linux安装 web2py,TurnkeyLinux上用于Web2Py到MySQL的DAL连接字符串
  8. LeetCode5 最长回文子串
  9. 推荐的Python电子书资源
  10. Labview双通道虚拟示波器完整程序 实现功能如下图
  11. python免费使用谷歌翻译的方法
  12. 【工作小技巧】cmd 批量移动文件
  13. pycharm导入.pyt后缀文件
  14. 【毕业设计源码】基于JAVA的自驾游小程序的设计与实现
  15. graphpad画生存曲线怎么样去掉删失点_手把手教你用GraphPad Prism绘制生存曲线
  16. 一篇文章让你了解大数据挖掘技术
  17. Linux内存管理(三十五):内存规整简介和 kcompactd详解
  18. 用HTML搭建3D立体相册网页,可放大缩小
  19. POST和GET请求,接码
  20. 想通过参加会议年入30万,没这些能力可不行——百格活动

热门文章

  1. numpy 矩阵运算
  2. 互动拍照 — 子弹时间
  3. R语言|plot和par函数绘图详解,绘图区域设置 颜色设置 绘图后修改及图像输出
  4. 闪存flash读写原理
  5. 巴比特独家 | 我们梳理98家新三板公司年报,发现企业布局区块链6大特点
  6. 四大开源IaaS软件云中较力
  7. 李宏毅老师《机器学习》课程笔记-1深度学习简介
  8. X站全称是什么_哔哩哔哩:b站的由来、233娘的拜年祭、霸屏的雷姆、站内界面变化...
  9. 基于Kears的Reuters新闻分类
  10. js前端构造json对象后台接收并反序列化