自旋锁(spinlock)在Linux中用于在多线程环境下保护共享资源。自旋锁在等待锁时会一直循环,适用于短时间持有锁的场景。互斥锁(mutex)是最常用的锁,当一个线程请求该锁时,如果锁已被占用,线程会被阻塞直到锁被释放。互斥锁与自旋锁不同的是,互斥锁竞争时会导致线程上下文切换,而自旋锁会一直占用CPU。当等待的开销小于上下文切换的开销时,我们可以选择使用自旋锁。
示例:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
pthread_spinlock_t spinlock;
pthread_mutex_t mutex;
int counter = 0;
void* increment(void* arg) {
for (int i = 0; i < 100000; ++i) {
pthread_spin_lock(&spinlock);
counter++;
pthread_spin_unlock(&spinlock);
}
return NULL;
}
void* increment2(void* arg) {
for (int i = 0; i < 100000; ++i) {
pthread_mutex_lock(&mutex);
counter++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
struct timeval start, end; // 统计时间
int timeuse;
pthread_t t1, t2;
pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
gettimeofday(&start, NULL);
pthread_create(&t1, NULL, increment, NULL);
pthread_create(&t2, NULL, increment, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
gettimeofday(&end, NULL);
pthread_spin_destroy(&spinlock);
timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
printf("spinlock use time: %d us\n", timeuse);
pthread_t t3, t4;
pthread_mutex_init (&mutex,NULL);
gettimeofday(&start, NULL);
pthread_create(&t3, NULL, increment2, NULL);
pthread_create(&t4, NULL, increment2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
gettimeofday(&end, NULL);
pthread_mutex_destroy(&mutex);
timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
printf("mutex use time: %d us\n", timeuse);
return 0;
}
编译运行我们可以得到类似如下的结果:
# ./a.out
spinlock use time: 7367 us
mutex use time: 16383 us
如此可以得出,当锁里的开销较小时使用自旋锁能提高效率。