文章目录
- 1. 互斥锁
- 2. 互斥锁示例代码
- 3. 读写锁
- 4. 读写锁示例代码
1. 互斥锁
如果信号量的值最多为1,就是共享资源在任意时刻最多只能有一个线程在访问,这样的逻辑称为“互斥”。这时有一种更加方便和语义更加准确的工具来满足这种逻辑,它就是互斥锁
使用互斥锁的步骤
- 声明互斥锁:
pthread_mutex_t m
- 初始化互斥锁:
pthread_mutex_init(&m, NULL)
- 加锁:
pthread_mutex_lock(&m);(阻塞加锁)或者pthread_mutex_trylock(&m);(非阻塞返回)
- 访问共享资源:
- 解锁:
pthread_mutex_unlock(&m);
- 销毁锁:
pthread_mutex_destroy(&m);
2. 互斥锁示例代码
下面的代码展示了两条线程如果使用互斥锁方式来互斥地访问标准输出
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t m; //定义一个互斥锁变量
void output(char * string){ //输出函数
const char *p = string;
while(*p != '\0'){
fprintf(stderr, "%c", *p);
usleep(100);
p++;
}
}
void * routine(void *argc){ //线程例程
//加锁
pthread_mutex_lock(&m);
//访问共享资源
output("message delivered by child\n");
//解锁
pthread_mutex_unlock(&m);
//线程退出
pthread_exit(NULL);
}
int main(int argc, char**argv){
//任何线程使用互斥锁之前都要进行初始化
pthread_mutex_init(&m, NULL);
//创建线程
pthread_t tid;
pthread_create(&tid, NULL, routine, NULL);
usleep(100);
//主线程访问公共资源
pthread_mutex_lock(&m); //加锁
output("Info output from parent\n"); //访问共享资源
pthread_mutex_unlock(&m); //解锁
//等待子线程退出,给子线程收尸
pthread_join(tid, NULL);
//销毁互斥锁
pthread_mutex_destroy(&m);
return 0;
}
互斥锁的使用非常方便,但它也有不适合的场合–假如要保护的资源在绝大多数情况下是读操作,就会导致这些本可以一起读的线程阻塞在互斥锁上, 资源得不到最大的利用。
3. 读写锁
互斥锁的低效率,是因为没有更加细致地区分如何访问共享资源,一刀切地在任何时候只有一个线程访问共享资源,而事实情况是读操作是可以同时进行,只有写操作才需要互斥,因此如果能根据访问目的–读或写,来分别加读锁和写锁,就能极大的提高效率(尤其是存在大量读写操作的情况下)
读/写锁的操作几乎跟任何互斥锁一样,唯一的区别是在加锁的时候可以选择加读锁和写锁
使用读写锁的步骤
- 声明读写锁:
pthread_rwlock_t rwlock;
- 初始化读写锁:
pthread_rwlock_init(&rwlock, NULL);
- 加写/读锁:
pthread_rwlock_wrlock(&rwlock);(写锁)或者pthread_rwlock_rdlock(&rwlock);(读锁)
- 访问共享资源:
- 解锁:
pthread_rwlock_unlock(&rwlock);
- 销毁锁:
pthread_rwlock_destroy(&rwlock);
4. 读写锁示例代码
下面的代码展示了如何使用读写锁
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static pthread_rwlock_t rwlock; //声明读写锁
int global = 0; //全局变量
void* routine1(void *argc){
//对共享资源进行写操作之前,必须加写锁(互斥锁)
pthread_rwlock_wrlock(&rwlock);
global += 1;
printf("I am %s, new global = %d\n", (char*)argc, global);
//释放锁
pthread_rwlock_unlock(&rwlock);
//退出线程
pthread_exit(NULL);
}
void* routine2(void *argc){
//对共享资源进行写操作之前,必须加写锁(互斥锁)
pthread_rwlock_wrlock(&rwlock);
global = 100;
printf("I am %s, new global = %d\n", (char*)argc, global);
//释放锁
pthread_rwlock_unlock(&rwlock);
//退出线程
pthread_exit(NULL);
}
void* routine3(void *argc){
//对共享资源进行读操作之前,必须读锁(共享锁)
pthread_rwlock_rdlock(&rwlock);
printf("I am %s, new global = %d\n", (char*)argc, global);
//释放锁
pthread_rwlock_unlock(&rwlock);
//退出线程
pthread_exit(NULL);
}
int main(int argc, char**argv){
//初始化读写锁
pthread_rwlock_init(&rwlock, NULL);
//创建3个线程,对共享资源同时进行读写操作
pthread_t tid1, tid2, tid3;
pthread_create(&tid1, NULL, routine1, "Thread 1");
pthread_create(&tid2, NULL, routine2, "Thread 2");
pthread_create(&tid3, NULL, routine3, "Thread 3");
//等待子线程结束
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
//销毁读写锁
pthread_rwlock_destroy(&rwlock);
return 0;
}