1.互斥锁
mutex是最常见的多线程同步的方法。多线程共享一个互斥量,得到锁的线程可以进入临界区执行代码。
mutex是睡眠等待(sleep waiting)类型的锁,当线程抢互斥锁失败的时候,线程会陷入休眠。优点就是节省CPU资源,缺点就是休眠唤醒会消耗一点时间。
// 声明一个互斥量
pthread_mutex_t mtx;
// 初始化
pthread_mutex_init(&mtx, NULL);
// 加锁
pthread_mutex_lock(&mtx);
// 解锁
pthread_mutex_unlock(&mtx);
// 销毁
pthread_mutex_destroy(&mtx);
C语言的demo1
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex;
char* buf[5];
int pos;
void* task(void *p) {
pthread_mutex_lock(&mutex);
buf[pos] = (char*)p;
sleep(1);
++ pos;
pthread_mutex_unlock(&mutex);
}
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, task, (void*)"zhangfei");
pthread_create(&tid2, NULL, task, (void*)"guanyu");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_mutex_destroy(&mutex);
int i = 0;
for (; i < pos; ++ i) {
printf("%s\n", buf[i]);
}
return 0;
}
2.条件变量
条件变量不是锁,它是一种线程间的通讯机制,并且几乎总是和互斥量一起使用的。所以互斥量和条件变量二者一般是成套出现的。
3.读写锁
读写锁,就是对于临界区区分读和写。在读多写少的场景下,不加区分的使用互斥量显然是有点浪费的。
读写锁的特性:
当读写锁被加了写锁时,其他线程对该锁加读锁或者写锁都会阻塞(不是失败)。
当读写锁被加了读锁时,其他线程对该锁加写锁会阻塞,加读锁会成功。
4.自旋锁
自旋锁(busy waiting),只不过自旋锁不会引起线程休眠。当共享资源的状态不满足的时候,自旋锁会不停地循环检测状态。因为不会陷入休眠,而是忙等待的方式也就不需要条件变量。
这是优点也是缺点。不休眠就不会引起上下文切换,但是会比较浪费CPU。