我非常好奇于不同同步原理的性能,于是对atomic, spinlock和mutex做了如下实验来比较:

1. 无同步的情况

 #include <future>
#include <iostream> volatile int value = ; int loop (bool inc, int limit) {
std::cout << "Started " << inc << " " << limit << std::endl;
for (int i = ; i < limit; ++i) {
if (inc) {
++value;
} else {
--value;
}
}
return ;
} int main () {
auto f = std::async (std::launch::async, std::bind(loop, true, ));//开启一个线程来执行loop函数,c++11的高级特性
loop (false, );
f.wait ();
std::cout << value << std::endl;
}

通过clang编译器:

 clang++ -std=c++ -stdlib=libc++ -O3 -o test test.cpp && time ./test

运行:

 SSttaarrtteedd    

 real    0m0.070s
user 0m0.089s
sys 0m0.002s

从运行结果很显然的我们可以看出增减不是原子性操作的,变量value最后所包含的值是不确定的(垃圾)。

2. 汇编LOCK

 #include <future>
#include <iostream> volatile int value = ; int loop (bool inc, int limit) {
std::cout << "Started " << inc << " " << limit << std::endl;
for (int i = ; i < limit; ++i) {
if (inc) {
asm("LOCK");
++value;
} else {
asm("LOCK");
--value;
}
}
return ;
} int main () {
auto f = std::async (std::launch::async, std::bind(loop, true, )); //开启一个线程来执行loop函数,c++11的高级特性
loop (false, );
f.wait ();
std::cout << value << std::endl;
}
 SSttaarrtteedd    

 real    0m0.481s
user 0m0.779s
sys 0m0.005s

  在最后变量value得到了正确的值,但是这些代码是不可移植的(平台不兼容的),只能在X86体系结构的硬件上运行,而且要想程序能正确运行编译的时候必须使用-O3编译选项。另外,由于编译器会在LOCK指令和增加或者减少指令之间注入其他指令,因此程序很容易出现“illegal instruction”异常从而导致程序被崩溃。

3. 原子操作atomic

 #include <future>
#include <iostream>
#include "boost/interprocess/detail/atomic.hpp" using namespace boost::interprocess::ipcdetail; volatile boost::uint32_t value = ; int loop (bool inc, int limit) {
std::cout << "Started " << inc << " " << limit << std::endl;
for (int i = ; i < limit; ++i) {
if (inc) {
atomic_inc32 (&value);
} else {
atomic_dec32 (&value);
}
}
return ;
} int main () {
auto f = std::async (std::launch::async, std::bind (loop, true, ));
loop (false, );
f.wait ();
std::cout << atomic_read32 (&value) << std::endl;
}

运行:

 SSttaarrtteedd    

 real    0m0.457s
user 0m0.734s
sys 0m0.004s

最后结果是正确的,从所用时间来看跟汇编LOCK的差不多。当然原子操作的底层也是使用了LOCK汇编来实现的,只不过是使用了可移植的方法而已。

4. 自旋锁spinlock

 #include <future>
#include <iostream>
#include "boost/smart_ptr/detail/spinlock.hpp" boost::detail::spinlock lock;
volatile int value = ; int loop (bool inc, int limit) {
std::cout << "Started " << inc << " " << limit << std::endl;
for (int i = ; i < limit; ++i) {
std::lock_guard<boost::detail::spinlock> guard(lock);
if (inc) {
++value;
} else {
--value;
}
}
return ;
} int main () {
auto f = std::async (std::launch::async, std::bind (loop, true, ));
loop (false, );
f.wait ();
std::cout << value << std::endl;
}

运行:

 SSttaarrtteedd    

 real    0m0.541s
user 0m0.675s
sys 0m0.089s

最后结果是正确的,从用时来看比上述的慢点,但是并没有慢太多

5. 互斥锁mutex

 #include <future>
#include <iostream> std::mutex mutex;
volatile int value = ; int loop (bool inc, int limit) {
std::cout << "Started " << inc << " " << limit << std::endl;
for (int i = ; i < limit; ++i) {
std::lock_guard<std::mutex> guard (mutex);
if (inc) {
++value;
} else {
--value;
}
}
return ;
} int main () {
auto f = std::async (std::launch::async, std::bind(loop, true, ));
loop (false, );
f.wait ();
std::cout << value << std::endl;
}

运行:

 SSttaarrtteedd    

 real    0m25.229s
user 0m7.011s
sys 0m22.667s

互斥锁要比前面几种的慢很多

 Benchmark
Method Time (sec.)
No synchronization 0.070
LOCK 0.481
Atomic 0.457
Spinlock 0.541
Mutex 22.667

当然,测试结果会依赖于不同的平台和编译器(我是在Mac Air和clang上做的测试)。

原文链接:http://demin.ws/blog/english/2012/05/05/atomic-spinlock-mutex/

atomic, spinlock and mutex性能比较的更多相关文章

  1. std::atomic和std::mutex区别

    ​ ​std::atomic介绍​ ​模板类std::atomic是C++11提供的原子操作类型,头文件 #include<atomic>.​在多线程调用下,利用std::atomic可实 ...

  2. 内核必看: spinlock、 mutex 以及 semaphore

    linux 内核的几种锁介绍 http://wenku.baidu.com/link?url=RdvuOpN3RPiC5aY0fKi2Xqw2MyTnpZwZbE07JriN7raJ_L6Ss8Ru1 ...

  3. Pthreads并行编程之spin lock与mutex性能对比分析(转)

    POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API.线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用 ...

  4. spinlock,mutex,semaphore,critical section的作用与差别

    某年深信服的笔试题,考的就是多线程的同步.简单的解释下方便记忆: 1.spinlock:自旋锁.是专为防止多处理器并发而引入的一种锁. 2.mutex:相互排斥量. 仅仅有拥有相互排斥对象的线程才有訪 ...

  5. Any race is a bug. When there is a race, the compiler is free to do whatever it wants.

    https://mp.weixin.qq.com/s/pVJiFdDDKVx707eKL19bjA 谈谈 Golang 中的 Data Race 原创 ms2008 poslua 2019-05-13 ...

  6. Samsung_tiny4412(驱动笔记07)----spinlock,semaphore,atomic,mutex,completion,interrupt

    /*********************************************************************************** * * spinlock,se ...

  7. 浅谈Unity的渲染优化(1): 性能分析和瓶颈判断(上篇)

    http://www.taidous.com/article-667-1.html 前言 首先,这个系列文章做个大致的介绍,题目"浅谈Unity",因为公司和国内大部分3D手游开发 ...

  8. go sync.Mutex 设计思想与演化过程 (一)

    go语言在云计算时代将会如日中天,还抱着.NET不放的人将会被淘汰.学习go语言和.NET完全不一样,它有非常简单的runtime 和 类库.最好的办法就是将整个源代码读一遍,这是我见过最简洁的系统类 ...

  9. 【linux】spinlock 的实现

    一.什么是spinlock spinlock又称自旋锁,是实现保护共享资源而提出一种锁机制.自旋锁与互斥锁比较类似,都是为了解决对某项资源的互斥使用 无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一 ...

随机推荐

  1. [CLR via C#]19. 可空值类型

    我们知道,一个值类型的变量永远不可能为null.它总是包含值类型本身.遗憾的是,这在某些情况下会成为问题.例如,设计一个数据库时,可将一个列定义成为一个32位的整数,并映射到FCL的Int32数据类型 ...

  2. mybatis generator with oracle

    1.generator.xml <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generat ...

  3. mysql oom之后的page 447 log sequence number 292344272 is in the future

    mysql oom之后,重启时发生130517 16:00:10 InnoDB: Error: page 447 log sequence number 292344272InnoDB: is in ...

  4. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q57-Q59)

    Question 57You update a solution validator.You need to ensure that all SharePoint solutions are vali ...

  5. NodeJS: 处理request网页乱码问题

    对于gb2312编码的网页,直接用request去获取会得到乱码的结果,解决方法很简单: 1. npm install iconv-lite 2. var iconv = require('iconv ...

  6. 【转】内部Handler类引起内存泄露

    如果您在Activity中定义了一个内部Handler类,如下代码: public class MainActivity extends Activity {       private  Handl ...

  7. WebRTC for UWP

    首先还是简单的介绍下webRTC吧: WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术,是谷歌2 ...

  8. CSS 类选择器(四)

    一.类选择器 类选择用使用"."(英文点号)进行标识,后面紧跟类名 如: .red{color:red;} 类样式可以应用于文档中的多个元素,这体现了CSS代码的可重用性,帮助用户 ...

  9. Swift面向对象基础(上)——Swift中的类和结构体(上)

    学习来自<极客学院> import Foundation //1.定义类和结构体 /* [修饰符]calss 类名{ 零到多个构造器 零到多个属性 零到多个方法 零到多个下标 } 修饰符可 ...

  10. Resharper注册机实现以及源代码

    一直用Resharper,每次找注册机也麻烦,就想怎么才能自己能做个注册机,把它原理给搞懂了,不就不用找了.今天早上起来研究了下Resharper注册机,网上找到一位大神之前做Resharper注册机 ...