操作系统编程--线程同步问题
1. 互斥量
-
互斥量是最简单的线程同步的方法
-
互斥量(互斥锁),处于两态之一的变量:解锁和加锁
-
两个状态可以保证资源访问的串行
-
操作系统直接提供了互斥量的API
-
开发者可以直接使用API完成资源的加锁、解锁操作
具体操作
◆ pthread_mutex_t //用于定义线程互斥锁对象
◆ pthread_mutex_lock(&mutex) //上锁操作
◆ pthread_mutex_unlock(&mutex) //开锁操作
#include
#include
#include
#include
#include
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int num = 0;
void *producer(void*){
int times = 10000000;
while(times --){ //不加锁操作则会导致出现共享资源不统一问题 即num 最后不为0
pthread_mutex_lock(&mutex);
num += 1;
pthread_mutex_unlock(&mutex);
}
}
void *comsumer(void*){
int times = 10000000;
while(times --){
pthread_mutex_lock(&mutex);
num -= 1;
pthread_mutex_unlock(&mutex);
}
}
int main(){
printf("Start in main function.");
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, &producer, NULL);
pthread_create(&thread2, NULL, &comsumer, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Print in main function: num = %d\n", num);
return 0;
}
编译运行
g++ Thread_Mutex.cpp -o Thread_Mutex -lpthread //编译 -lpthread用于连接动态库
./Thread_Mutex //运行
2. 自旋锁
特点:
- 自旋锁也是一种多线程同步的变量
- 使用自旋锁的线程会反复检查锁变量是否可用
- 自旋锁不会让出CPU,是一种忙等待状态
- 自旋锁避免了进程或线程上下文切换的开销
- 操作系统内部很多地方使用的是自旋锁
- 自旋锁不适合在单核CPU使用
用到的函数和变量
pthread_spinlock_t
pthread_ spinlock _lock
pthread_ spinlock _unlock
代码实现:
#include
#include
#include
//临界资源
int num = 0;
pthread_spinlock_t spinlock;
//PRODUCER
void *producer(void *) {
int time = 10000000;
while (time--) {
pthread_spin_lock(&spinlock);
num += 1;
pthread_spin_unlock(&spinlock);
}
}
//CONSUMER
void *consumer(void *) {
int time = 10000000;
while(time--) {
pthread_spin_lock(&spinlock);
num -= 1;
pthread_spin_unlock(&spinlock);
}
}
int main() {
printf("Start int main function.\n");
pthread_t thread1, thread2;
pthread_spin_init(&spinlock, 0);//初始化后使用
pthread_create(&thread1, NULL , &producer, NULL);
pthread_create(&thread2, NULL , &consumer, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("The number is %d\n", num);
return 0;
}
3. 读写锁
应用场景:
- 临界资源多读少写
- 读取的时候并不会改变临界资源的值
特点:
- 读写锁是一种特殊的自旋锁
- 允许多个读者同时访问资源以提高读性能
- 对于写操作则是互斥的
涉及到的函数:
pthread_rwlock_t
pthread_rwlock_rdlock(读锁)
pthread_rwlock_wrlock(写锁)
代码实现:
#include
#include
#include
#include
//临界资源
int num = 0;
//Writer
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void *writer(void *) {
int time = 100000;
while (time --) {
pthread_rwlock_wrlock(&rwlock);//when need to do write operation lock it. forbid other write or read operation.
num += 1;
pthread_rwlock_unlock(&rwlock);//unlock it when done.
}
}
//Reader
void *reader(void *) {
int time = 100000;
while(time--) {
if (time % 1000 == 0) {
pthread_rwlock_rdlock(&rwlock);//when need to do write operation lock it. forbid other write or read operation.
printf("The number is %d\n",num);
pthread_rwlock_unlock(&rwlock);//unlock it when done.
}
}
}
int main() {
printf("Start int main function.\n");
pthread_t thread1, thread2, thread3;
pthread_create(&thread1, NULL , &reader, NULL);
pthread_create(&thread2, NULL , &reader, NULL);
pthread_create(&thread3, NULL , &writer, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
printf("The number is %d\n", num);
return 0;
}
条件变量 -- 缓冲区
特点:
- 条件变量是一种相对复杂的线程同步方法
- 条件变量允许线程睡眠,直到满足某种条件
- 当满足条件时,可以向该线程信号,通知唤醒
应用场景:
- 缓冲区小于等于0时,不允许消费者消费,消费者必须等待
- 缓冲区满时,不允许生产者往缓冲区生产,生产者必须等待
使用到的函数
pthread_cond_t
pthread_cond_wait(等待条件满足)
pthread_cond_signal(等待被唤醒)
代码实现:
#include
#include
#include
#include
//临界资源
int num = 0;
int MAX_BUF = 100;//缓冲区
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//PRODUCER
void *producer(void *) {
int time = 10000000;
while (time--) {
pthread_mutex_lock(&mutex);//lock -- mutex
while (num >= MAX_BUF) {
pthread_cond_wait(&cond,&mutex); // When run to this, The process change to block status and wait the signal to awake it.
printf("This BUf is full.\n");
}
num += 1; // num <= MAX_BUF , so produce one product.
printf("The current goods number is :%d\n", num);
sleep(1);//produce a product cost one second.
pthread_cond_signal(&cond); // send signal.
printf("notify the consumer!!\n");
pthread_mutex_unlock(&mutex);// unlock -- mutex
sleep(1);
}
}
//CONSUMER
void *consumer(void *) {
int time = 10000000;
while(time--) {
pthread_mutex_lock(&mutex);
while (num <= 0) {
pthread_cond_wait(&cond, &mutex);
printf("The BUF is empty!!\n");
}
num -= 1; // num > 0, so consume one product.
printf("Consumed one thing!,remain : %d\n", num);
sleep(1); // cost one sec to consume.
pthread_cond_signal(&cond); // send signal to awake the other process.
printf("notify the producer!!\n");
pthread_mutex_unlock(&mutex);
}
}
int main() {
printf("Start int main function.\n");
pthread_t thread1, thread2;
pthread_create(&thread1, NULL , &producer, NULL);
pthread_create(&thread2, NULL , &consumer, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("The number is %d\n", num);
return 0;
}