Yebangyu's Blog

Fond of Concurrency Programming and Machine Learning

Spinlock and mutex

Spinlock(自旋锁)和mutex作为两种互斥锁,在并行编程中都得到了广泛应用。那么,这两种锁有什么区别吗?

当一个线程对Spinlock加锁时,如果该锁被其他线程占用,那么该线程会通过一个loop不断地重试( try again and again);而使用mutex的线程没有得到锁时,会sleep。

因为,当临界区较短时,Spinlock因为没有上下文切换,可能性能更优;当临界区较长时,不断的spin将浪费大量的cpu资源。

如何实现一个Spinlock呢?下面简单封装了一下,并在Ubuntu 14.04 32bit系统,X86体系结构,Intel I5双核处理器环境下,测试相应的性能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<thread>
using namespace std;
int counter = 0;
int lock = 0;
void spin_lock()
{
  while(__sync_lock_test_and_set(&lock, 1));
}
void spin_unlock()
{
  __sync_lock_release(&lock);
}
void f()
{
  for (int i = 0; i <  10000000; i++) {
    spin_lock();
    counter = counter + 2;//tiny critical section
    spin_unlock();
  }
}
int main()
{
  thread t1(f);
  thread t2(f);
  t1.join();
  t2.join();
  return 0;
}

2个线程时,这个程序的运行时间为:

real	0m1.082s
user	0m2.060s
sys	0m0.000s

4个线程时:

real	0m5.701s
user	0m19.400s
sys	0m0.000s

如果改为std::mutex(lock和unlock成员函数)呢?对比一下:

2个线程:

real	0m3.081s
user	0m2.796s
sys	0m3.344s

4个线程:

real	0m5.860s
user	0m6.004s
sys	0m14.936s

不难发现,由于大量的上下文切换,使用mutex时,花在sys上的时间要远比使用Spinlock的要多。

小结

以下两种情况,应该考虑使用spinlock代替mutex:

1,每个processor上(只)运行一个线程。

2,线程平均等待(spin)时间少于两次上下文切换的开销。

当然,一切都离不开实际的测试和分析。

下次,我们将研究更多、更高效的spinlock实现。