atomic, spinlock and mutex性能比较

https://blog.csdn.net/cywosp/article/details/8987593

 

atomic, spinlock and mutex性能比较

转载请说明出处:http://blog.csdn.net/cywosp/article/details/8987593

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

1. 无同步的情况

#include <future>
#include <iostream>

volatile int value = 0;

int loop (bool inc, int limit) {
  std::cout << "Started " << inc << " " << limit << std::endl;
  for (int i = 0; i < limit; ++i) {
    if (inc) { 
      ++value;
    } else {
      --value;
    }
  }
  return 0;
}

int main () {
  auto f = std::async (std::launch::async, std::bind(loop, true, 20000000));//开启一个线程来执行loop函数,c++11的高级特性
  loop (false, 10000000);
  f.wait ();
  std::cout << value << std::endl;
}

通过clang编译器:

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

#include <future>
#include <iostream>

volatile int value = 0;

int loop (bool inc, int limit) {
  std::cout << "Started " << inc << " " << limit << std::endl;
  for (int i = 0; i < limit; ++i) {
    if (inc) { 
      asm("LOCK");
      ++value;
    } else {
      asm("LOCK");
      --value;
    }
  }
  return 0;
}

int main () {
  auto f = std::async (std::launch::async, std::bind(loop, true, 20000000)); //开启一个线程来执行loop函数,c++11的高级特性
  loop (false, 10000000);
  f.wait ();
  std::cout << value << std::endl;
} 

运行:

 
  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

#include <future>
#include <iostream>
#include "boost/interprocess/detail/atomic.hpp"

using namespace boost::interprocess::ipcdetail;

volatile boost::uint32_t value = 0;

int loop (bool inc, int limit) {
  std::cout << "Started " << inc << " " << limit << std::endl;
  for (int i = 0; i < limit; ++i) {
    if (inc) { 
      atomic_inc32 (&value);
    } else {
      atomic_dec32 (&value);
    }
  }
  return 0;
}

int main () {
  auto f = std::async (std::launch::async, std::bind (loop, true, 20000000));
  loop (false, 10000000);
  f.wait ();
  std::cout << atomic_read32 (&value) << std::endl;
}

运行:

 
  1. SSttaarrtteedd 10 2100000000000000

  2.  
  3. 10000000

  4.  
  5. real 0m0.457s

  6. user 0m0.734s

  7. 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 = 0;

int loop (bool inc, int limit) {
  std::cout << "Started " << inc << " " << limit << std::endl;
  for (int i = 0; i < limit; ++i) {
    std::lock_guard<boost::detail::spinlock> guard(lock);
    if (inc) { 
      ++value;
    } else {
      --value;
    }
  }
  return 0;
}

int main () {
  auto f = std::async (std::launch::async, std::bind (loop, true, 20000000));
  loop (false, 10000000);
  f.wait ();
  std::cout << value << std::endl;
}

运行:

 
  1. SSttaarrtteedd 10 2100000000000000

  2.  
  3. 10000000

  4.  
  5. real 0m0.541s

  6. user 0m0.675s

  7. sys 0m0.089s

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

 

5. 互斥锁mutex

#include <future>
#include <iostream>

std::mutex mutex;
volatile int value = 0;

int loop (bool inc, int limit) {
  std::cout << "Started " << inc << " " << limit << std::endl;
  for (int i = 0; i < limit; ++i) {
    std::lock_guard<std::mutex> guard (mutex);
    if (inc) { 
      ++value;
    } else {
      --value;
    }
  }
  return 0;
}

int main () {
  auto f = std::async (std::launch::async, std::bind(loop, true, 20000000));
  loop (false, 10000000);
  f.wait ();
  std::cout << value << std::endl;
}

运行:

 
  1. SSttaarrtteedd 10 2010000000000000

  2.  
  3. 10000000

  4.  
  5. real 0m25.229s

  6. user 0m7.011s

  7. sys 0m22.667s

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

Benchmark

MethodTime (sec.)
No synchronization0.070
LOCK0.481
Atomic0.457
Spinlock0.541
Mutex22.667

 

当然,测试结果会依赖于不同的平台和编译器(我是在Mac Air和clang上做的测试)。But for me it was quite interesting to see that spinlock, in spite of its more sophisticated implementation comparing to atomics, works not much slower.

Sadly, my clang 3.1 still doesn’t support atomic, and I had to use boost.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值