atomic, spinlock and mutex性能比較,spinlockmutex
我非常好奇於不同同步原理的性能,於是對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 }
View Code
通過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 }
View Code
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 }
View Code
運行:
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 }
View Code
運行:
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 }
View Code
運行:
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/