通过atomic_flag简单自旋锁实现简单说明标准库中锁使用的memory_order
在使用标准库中的加锁机制时,例如我们使用std::mutex,写了如下的代码(下面的代码使用condition_variable可能更合适)
std::mutex g_mtx;
int g_resNum;
// and how to get the resource
... // 线程1使用如下代码:
{
std::lock_guard<std::mutex> guard(g_mtx);
// prepare the resource
...
// set the resource num
g_resNum = ...;
} // 线程2使用如下的代码:
{
std::lock_guard<std::mutex> guard(g_mtx);
// check the g_resNum
if (g_resNum > )
{
...
}
}
我们知道如果先运行线程1的代码,也就是说线程1获得了锁,进行了准备资源的操作。然后运行线程2,也就是说线程2之后获得了锁,可以知道线程1加锁区域的代码已经执行完毕,而且对线程2可见,我们可以放心的使用线程1中设置的资源。这里面的原因是
标准库在实现std::mutex过程中使用了memory_order。http://en.cppreference.com/w/cpp/atomic/memory_order 中的描述如下:
Acquire operation
Atomic load with memory_order_acquire or stronger is an acquire operation. The lock() operation on a Mutex is also an acquire operation.
Release operation
Atomic store with memory_order_release or stronger is a release operation. The unlock() operation on a Mutex is also a release operation.
C++ atomic中对Acquire- Release ordering的简单介绍如下:
If an atomic store in thread A is tagged memory_order_release and an atomic load in thread B from the same variable is tagged memory_order_acquire, all memory writes (non-atomic and relaxed atomic) that happened-before the atomic store from the point of view of thread A, become visible side-effects in thread B, that is, once the atomic load is completed, thread B is guaranteed to see everything thread A wrote to memory.
关于memory_order的简单介绍就到这里,下面我用一个很简单的spinlock的实现来简单说明一下memory_order的使用:
class spinlock_mutex
{
std::atomic_flag flag;
public:
spinlock_mutex() :
flag(ATOMIC_FLAG_INIT)
{} void lock()
{
while(flag.test_and_set(std::memory_order_acquire));
} bool try_lock()
{
if (flag.test_and_set(std::memory_order_acquire))
return false; return true;
} void unlock()
{
flag.clear(std::memory_order_release);
}
};
上述spinlock实现存在性能上的问题,网上有关于这个实现问题的讨论,参考网址:https://www.zhihu.com/question/55764216
希望能给初学C++标准库多线程的程序员有所启示。
通过atomic_flag简单自旋锁实现简单说明标准库中锁使用的memory_order的更多相关文章
- 在C++11编译环境中,简单自测了一下C++标准库中的string/vector和迭代器,记录一下
#include <iostream> #include <vector> using namespace std; int main() { //////////////// ...
- 如何美观地打印 Python 对象?这个标准库可以简单实现
前不久,我写了一篇文章回顾 Python 中 print 的发展历史 ,提到了两条发展线索: 明线:早期的 print 语句带有 C 和 Shell 的影子,是个应用程序级的 statement,在最 ...
- SQL Server中的锁的简单学习
简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的 ...
- Innodb 锁 (简单笔记)
看过很多innodb锁的文章,已经明白的就不写了,简单做个笔记 Innodb 锁的兼容性: 1.意向锁和意向锁之间都是兼容的 2.X(排他锁)与任何锁都是不兼容的 3.排他意向锁 IX 于S锁是不 ...
- Redisson分布式锁的简单使用
一:前言 我在实际环境中遇到了这样一种问题,分布式生成id的问题!因为业务逻辑的问题,我有个生成id的方法,是根据业务标识+id当做唯一的值! 而uuid是递增生成的,从1开始一直递增,那么在同一台机 ...
- Mysql锁机制简单了解一下
历史文章推荐: 可能是最漂亮的Spring事务管理详解 面试中关于Java虚拟机(jvm)的问题看这篇就够了 Java NIO 概览 关于分布式计算的一些概念 一 锁分类(按照锁的粒度分类) Mysq ...
- Redis分布式锁实现简单秒杀功能
这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...
- Java内置锁和简单用法
一.简单的锁知识 关于内置锁 Java具有通过synchronized关键字实现的内置锁,内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁. jav ...
- 单实例redis分布式锁的简单实现
redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com. ...
随机推荐
- EasyUI datagrid 一个可以 直接运行例子一个文件 六
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta ht ...
- heap 的一些用法
noip 合并果子 #include<bits/stdc++.h> using namespace std; int heap[maxn]; ; void input(int d) { ...
- canvas的认识,时钟的设置
canvas的三要素:ID标识,width宽度,height高度,他是行元素 IE9才支持canvas,canvas是一个透明的画板,要用js去画 绘制一个圆 线性渐变颜色 径向渐变 图片的绘制: 视 ...
- JOISC2019 简要题解
第18回 日本情報オリンピック 春合宿 オンラインコンテスト (JOISC2019) 官网 Day 1 試験 (Examination) description 有\(N\)个学生,每个学生有两科成绩 ...
- 【BZOJ3672】【UOJ#6】【NOI2014】随机数生成器
暴力出奇迹 原题: 2≤N,M≤5000 0≤Q≤50000 0≤a≤300 0≤b,c≤108 0≤x0<d≤108 1≤ui,vi≤N×M 恩首先容易看出来这个棋盘直接模拟搞出来就行了,不用 ...
- Fedora Redhat Centos 有什么区别和关系?
Fedora Redhat Centos 有什么区别和关系? 经常看到有人讨论服务器的操作系统,比如 Readhat 和 Centos,还有 Ubuntu Server. 可能 Ubuntu Serv ...
- Git中清除远程仓库HTTPS认证信息的方法
Git远程仓库同步时用户认证有两种方式:HTTPS.SSH,对应的Git仓库上有两个不同的链接地址. https方式使用账号和密码授权,简单易用,便于进行权限细分管理,而且防火墙一般会打开 http ...
- requestAnimationFrame 持续动画效果
1. requestAnimationFrame 概述 requestAnimationFrame 是浏览器用于定时循环操作的一个API, 类似于setTimeout, 主要用途是按帧对网页进行重绘. ...
- bootstrap-table设置表头宽度无效的解决方案
bootstrap-table设置colmuns中某列的宽度无效时,需要给整个表设置css属性: .table { table-layout: fixed; }
- 代理模式proxy
代理模式的共同优点如下: (1) 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度. (2) 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵 ...