http://www.parallellabs.com/2010/01/31/pthreads-programming-spin-lock-vs-mutex-performance-analysis/ 

POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API。线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间共 享的临界区(Critical Section)进行保护(另一种常用的同步机制是barrier)。

Pthreads提供了多种锁机制:
(1) Mutex(互斥量):pthread_mutex_***
(2) Spin lock(自旋锁):pthread_spin_***
(3) Condition Variable(条件变量):pthread_con_***
(4) Read/Write lock(读写锁):pthread_rwlock_***

Pthreads提供的Mutex锁操作相关的API主要有:
pthread_mutex_lock (pthread_mutex_t *mutex);
pthread_mutex_trylock (pthread_mutex_t *mutex);
pthread_mutex_unlock (pthread_mutex_t *mutex);

Pthreads提供的与Spin Lock锁操作相关的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);

从实现原理上来讲,Mutex属于sleep-waiting类型的锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在 Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程 A就会被阻塞(blocking),Core0 会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其他的任务(例如另一个线程C)而不必进行忙等待。而Spin lock则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在 Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。

如果大家去查阅Linux glibc中对pthreads API的实现NPTL(

001 // Name: spinlockvsmutex1.cc
003 // Compiler(spin lock version): g++ -o spin_version -DUSE_SPINLOCK spinlockvsmutex1.cc -lpthread
004 // Compiler(mutex version): g++ -o mutex_version spinlockvsmutex1.cc -lpthread
005 #include <stdio.h>
006 #include <unistd.h>
007 #include <sys/syscall.h>
008 #include <errno.h>
009 #include <sys/time.h>
010 #include <list>
011 #include <pthread.h>
012  
013 #define LOOPS 50000000
014  
015 using namespace std;
016  
017 list<int> the_list;
018  
019 #ifdef USE_SPINLOCK
020 pthread_spinlock_t spinlock;
021 #else
022 pthread_mutex_t mutex;
023 #endif
024  
025 //Get the thread id
026 pid_t gettid() { return syscall( __NR_gettid ); }
027  
028 void *consumer(void *ptr)
029 {
030     int i;
031  
032     printf("Consumer TID %lun", (unsigned long)gettid());
033  
034     while (1)
035     {
036 #ifdef USE_SPINLOCK
037         pthread_spin_lock(&spinlock);
038 #else
039         pthread_mutex_lock(&mutex);
040 #endif
041  
042         if (the_list.empty())
043         {
044 #ifdef USE_SPINLOCK
045             pthread_spin_unlock(&spinlock);
046 #else
047             pthread_mutex_unlock(&mutex);
048 #endif
049             break;
050         }
051  
052         i = the_list.front();
053         the_list.pop_front();
054  
055 #ifdef USE_SPINLOCK
056         pthread_spin_unlock(&spinlock);
057 #else
058         pthread_mutex_unlock(&mutex);
059 #endif
060     }
061  
062     return NULL;
063 }
064  
065 int main()
066 {
067     int i;
068     pthread_t thr1, thr2;
069     struct timeval tv1, tv2;
070  
071 #ifdef USE_SPINLOCK
072     pthread_spin_init(&spinlock, 0);
073 #else
074     pthread_mutex_init(&mutex, NULL);
075 #endif
076  
077     // Creating the list content...
078     for (i = 0; i < LOOPS; i++)
079         the_list.push_back(i);
080  
081     // Measuring time before starting the threads...
082     gettimeofday(&tv1, NULL);
083  
084     pthread_create(&thr1, NULL, consumer, NULL);
085     pthread_create(&thr2, NULL, consumer, NULL);
086  
087     pthread_join(thr1, NULL);
088     pthread_join(thr2, NULL);
089  
090     // Measuring time after threads finished...
091     gettimeofday(&tv2, NULL);
092  
093     if (tv1.tv_usec > tv2.tv_usec)
094     {
095         tv2.tv_sec--;
096         tv2.tv_usec += 1000000;
097     }
098  
099     printf("Result - %ld.%ldn", tv2.tv_sec - tv1.tv_sec,
100         tv2.tv_usec - tv1.tv_usec);
101  
102 #ifdef USE_SPINLOCK
103     pthread_spin_destroy(&spinlock);
104 #else
105     pthread_mutex_destroy(&mutex);
106 #endif
107  
108     return 0;
109 }

相关文章:

  • 2022-12-23
  • 2022-01-06
  • 2022-12-23
  • 2021-09-23
  • 2021-09-27
  • 2022-12-23
  • 2022-02-20
  • 2021-07-25
猜你喜欢
  • 2022-12-23
  • 2021-05-26
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-14
  • 2021-07-06
相关资源
相似解决方案