atomic, spinlock and mutex性能比较

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

1. 无同步的情况

 1 #include <future>
 2 #include <iostream>
 3
 4 volatile int value = 0;
 5
 6 int loop (bool inc, int limit) {
 7   std::cout << "Started " << inc << " " << limit << std::endl;
 8   for (int i = 0; i < limit; ++i) {
 9     if (inc) {
10       ++value;
11     } else {
12       --value;
13     }
14   }
15   return 0;
16 }
17
18 int main () {
19   auto f = std::async (std::launch::async, std::bind(loop, true, 20000000));//开启一个线程来执行loop函数,c++11的高级特性
20   loop (false, 10000000);
21   f.wait ();
22   std::cout << value << std::endl;
23 }

通过clang编译器:

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

运行:

1 SSttaarrtteedd  10  2100000000000000
2
3 11177087
4
5 real    0m0.070s
6 user    0m0.089s
7 sys 0m0.002s

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

2. 汇编LOCK

 1 #include <future>
 2 #include <iostream>
 3
 4 volatile int value = 0;
 5
 6 int loop (bool inc, int limit) {
 7   std::cout << "Started " << inc << " " << limit << std::endl;
 8   for (int i = 0; i < limit; ++i) {
 9     if (inc) {
10       asm("LOCK");
11       ++value;
12     } else {
13       asm("LOCK");
14       --value;
15     }
16   }
17   return 0;
18 }
19
20 int main () {
21   auto f = std::async (std::launch::async, std::bind(loop, true, 20000000)); //开启一个线程来执行loop函数,c++11的高级特性
22   loop (false, 10000000);
23   f.wait ();
24   std::cout << value << std::endl;
25 } 

1 SSttaarrtteedd  10  2000000100000000
2
3 10000000
4
5 real    0m0.481s
6 user    0m0.779s
7 sys 0m0.005s

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

3. 原子操作atomic

 1 #include <future>
 2 #include <iostream>
 3 #include "boost/interprocess/detail/atomic.hpp"
 4
 5 using namespace boost::interprocess::ipcdetail;
 6
 7 volatile boost::uint32_t value = 0;
 8
 9 int loop (bool inc, int limit) {
10   std::cout << "Started " << inc << " " << limit << std::endl;
11   for (int i = 0; i < limit; ++i) {
12     if (inc) {
13       atomic_inc32 (&value);
14     } else {
15       atomic_dec32 (&value);
16     }
17   }
18   return 0;
19 }
20
21 int main () {
22   auto f = std::async (std::launch::async, std::bind (loop, true, 20000000));
23   loop (false, 10000000);
24   f.wait ();
25   std::cout << atomic_read32 (&value) << std::endl;
26 }

运行:

1 SSttaarrtteedd  10  2100000000000000
2
3 10000000
4
5 real    0m0.457s
6 user    0m0.734s
7 sys 0m0.004s

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

4. 自旋锁spinlock

 1 #include <future>
 2 #include <iostream>
 3 #include "boost/smart_ptr/detail/spinlock.hpp"
 4
 5 boost::detail::spinlock lock;
 6 volatile int value = 0;
 7
 8 int loop (bool inc, int limit) {
 9   std::cout << "Started " << inc << " " << limit << std::endl;
10   for (int i = 0; i < limit; ++i) {
11     std::lock_guard<boost::detail::spinlock> guard(lock);
12     if (inc) {
13       ++value;
14     } else {
15       --value;
16     }
17   }
18   return 0;
19 }
20
21 int main () {
22   auto f = std::async (std::launch::async, std::bind (loop, true, 20000000));
23   loop (false, 10000000);
24   f.wait ();
25   std::cout << value << std::endl;
26 }

运行:

1 SSttaarrtteedd  10  2100000000000000
2
3 10000000
4
5 real    0m0.541s
6 user    0m0.675s
7 sys 0m0.089s

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

5. 互斥锁mutex

 1 #include <future>
 2 #include <iostream>
 3
 4 std::mutex mutex;
 5 volatile int value = 0;
 6
 7 int loop (bool inc, int limit) {
 8   std::cout << "Started " << inc << " " << limit << std::endl;
 9   for (int i = 0; i < limit; ++i) {
10     std::lock_guard<std::mutex> guard (mutex);
11     if (inc) {
12       ++value;
13     } else {
14       --value;
15     }
16   }
17   return 0;
18 }
19
20 int main () {
21   auto f = std::async (std::launch::async, std::bind(loop, true, 20000000));
22   loop (false, 10000000);
23   f.wait ();
24   std::cout << value << std::endl;
25 }

运行:

1 SSttaarrtteedd  10  2010000000000000
2
3 10000000
4
5 real    0m25.229s
6 user    0m7.011s
7 sys 0m22.667s

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

1 Benchmark
2 Method    Time (sec.)
3 No synchronization     0.070
4 LOCK     0.481
5 Atomic     0.457
6 Spinlock     0.541
7 Mutex     22.667

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

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

时间: 2024-10-24 23:14:34

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

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

某年深信服的笔试题,考的就是多线程的同步.简单的解释下方便记忆: 1.spinlock:自旋锁.是专为防止多处理器并发而引入的一种锁. 2.mutex:相互排斥量. 仅仅有拥有相互排斥对象的线程才有訪问公共资源的权限.保证了资源不会同一时候被多个线程訪问. 3.semaphore:信号量.同意多个线程同一时候訪问资源,限制訪问资源的最大线程数. 4.critical section:临界区. 随意时刻仅仅同意一个线程对共享资源进行訪问.

spinlock,mutex,semaphore,critical section的作用与区别

某年深信服的笔试题,考的就是多线程的同步,简单的解释下方便记忆: 1.spinlock:自旋锁.是专为防止多处理器并发而引入的一种锁. 2.mutex:互斥量.只有拥有互斥对象的线程才有访问公共资源的权限.保证了资源不会同时被多个线程访问. 3.semaphore:信号量.允许多个线程同时访问资源,限制访问资源的最大线程数. 4.critical section:临界区.任意时刻只允许一个线程对共享资源进行访问.

《Effective Modern C++》要点中英文对照

目录 CHAPTER 1 Deducing Types 章节1 类型推导 Item 1:Understand template type deduction. 条款1:理解模板类型推导. Item 2:Understand auto type deduction. 条款2:理解auto类型推导. Item 3:Understand decltype. 条款3:理解decltype. Item 4:Know how to view deduced types. 条款4:知道如何查看推导出来的类型.

Samsung_tiny4412(笔记)--&gt;spinlock,semaphore,atomic,mutex,completion,interrupt

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->spinlock,semaphore,atomic,mutex,completion,interrupt * * 声明: * 1. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因; * 2. 基于1中的原因,本文借鉴了python中的缩进代码风格进行代码的体现: *

关于signal, kill, mutex, spinlock的一些总结

用户进程,在用户态可以被直接 kill . 用户进程陷入内核,在内核态进入死循环: 1. 循环体中有 msleep_interruptible ,进程状态为S,即可中断的睡眠状态,kill 命令不能杀死进程. 2. 循环体中有 msleep ,进程状态为D,即不可中断的睡眠状态,kill 命令不能杀死进程. 3. 循环体中无 sleep ,进程状态为R,即可执行状态,kill 命令不能杀死进程. 以上三种情况,不能被kill是因为进程处于内核态,信号不会被处理,在进程退出内核态时,信号将会被处理

spinlock剖析与改进

http://www.searchtb.com/2011/06/spinlock%E5%89%96%E6%9E%90%E4%B8%8E%E6%94%B9%E8%BF%9B.html 1, spinlock介绍 spinlock又称自旋锁,线程通过busy-wait-loop的方式来获取锁,任何时刻时刻只有一个线程能够获得锁,其他线程忙等待直到获得锁.spinlock在多处理器多线程环境的场景中有很广泛的使用,一般要求使用spinlock的临界区尽量简短,这样获取的锁可以尽快释放,以满足其他忙等的

自旋锁spinlock剖析与改进

1, spinlock介绍 spinlock又称自旋锁,线程通过busy-wait-loop的方式来获取锁,任时刻只有一个线程能够获得锁,其他线程忙等待直到获得锁.spinlock在多处理器多线程环境的场景中有很广泛的使用,一般要求使用spinlock的临界区尽量简短,这样获取的锁可以尽快释放,以满足其他忙等的线程.Spinlock和mutex不同,spinlock不会导致线程的状态切换(用户态->内核态),但是spinlock使用不当(如临界区执行时间过长)会导致cpu busy飙高. ...

C线程同步

转自:http://dreamrunner.org/blog/2014/08/07/C-multithreading-programming/ Overview 随着多核 CPU 随处可见,多线程(multithreading)可以被用来实现并行,提高 CPU 的利用率和性能显著的提高.掌握多线程编程也成为现代实现软件的基本要求技能之一.Introduction to Parallel Computing详细的介绍了 Parallel Computing; 为什么使用它;Parallel Com

Linux多线程同步方式

当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图,当多个线程同时去修改这片内存时,就可能出现偏差,得到与预期不符合的值.为啥需要同步,一件事情逻辑上一定是有序的,即使在并发环境下:而操作系统对于多线程不会自动帮我们串行化,所以需要我们通过操作系统提供的同步方式api,结合自己的业务逻辑,利用多线程提高性能的同时,保证业务逻辑的正确性.一般而言,linux下同步方式主要有4种,原子锁,互斥量,读写锁和条件变量.下面一一介绍几种同步方式. 1. spinlock 1)  概念 spin