操作系统学习提升篇——线程同步

互斥量(互斥锁)

互斥量的工作原理:当一个线程访问临界资源时,对临界资源加锁,阻止另一个线程访问临界资源,使用完之后再进行解锁。

当两个线程的指令交叉执行,会导致线程同步的问题。互斥量可以保证先后执行,先执行完一个线程的相关指令,再执行另一个的相关指令。(原子性)

原子性:一系列操作不可被中断,要么全部执行完成,要么全部没有执行。

互斥量是最简单的线程同步的方法。
互斥量,处于两态之一的变量:解锁和加锁。两个状态可以保证资源访问的串行。

操作系统直接提供了互斥量的API,开发者可以直接使用API完成资源的加锁、解锁操作。C的API为:pthread_mutex_t。

// 互斥锁的例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//临界资源
int num=0;
//生产者
void *producer(void*){
	int times = 100000000;
	while(time--){
		pthread_mutex_lock(&mutex);
		num+=1;
		pthread_mutex_unlock(&mutex);
	}
}
//消费者
void *consumer(void*){
	int times = 100000000;
	while(time--){
		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,&consumer,NULL);
	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);
	printf("print in main function:num= %d\n",num);
	return 0;
}

自旋锁

自旋锁的工作原理:与互斥量相同,也是在使用临界资源时加锁,完成之后解锁释放,保证临界资源串行访问。

自旋锁也是一种多线程同步的变量。
使用自旋锁的线程会反复检查锁变量是否可用。
自旋锁不会让出CPU,是一种忙等待状态。
自旋锁是一种 死循环等待锁被释放 的锁。

自旋锁避免了进程或线程上下文切换的开销。
操作系统内部很多地方使用的是自旋锁。
自旋锁不适合在单核CPU使用。

C的API为:pthread_spinlock_t

// 自旋锁的例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
pthread_spinlock_t spin_lock;

//临界资源
int num=0;
//生产者
void *producer(void*){
	int times = 100000000;
	while(time--){
		pthread_spin_lock(&spin_lock);
		num+=1;
		pthread_spin_unlock(&spin_lock);
	}
}
//消费者
void *consumer(void*){
	int times = 100000000;
	while(time--){
		pthread_spin_lock(&spin_lock);
		num-=1;
		pthread_spin_unlock(&spin_lock);
	}
}
int main(){
	printf("start in main function.");
	pthread_spin_init(&spin_lock,0)
	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("print in main function:num= %d\n",num);
	return 0;
}

读写锁

当线程对临界资源多读少写时(例如对历史订单数据库,一般只会进行查看,而不会更改),读取的时候并不会改变临界资源的值,使用读写锁可以提高效率。

读写锁是一种特殊的自旋锁。
允许多个读者同时访问资源以提高读性能。
读和写之间是互斥的,读和读之间不互斥。

C的API为:pthread_rwlock_t

// 读写锁的例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER;

//临界资源
int num=0;
//读操作
void *reader(void*){
	int times = 100000000;
	while(time--){
		pthread_rwlock_rdlock(&rwlock);
		if(time%1000==0){
			usleep(10)
		}
		pthread_rwlock_unlock(&rwlock);
	}
}
//写操作
void *writer(void*){
	int times = 100000000;
	while(time--){
		pthread_rwlock_wdlock(&rwlock);
		num-=1;
		pthread_rwlock_unlock(&rwlock);
	}
}
int main(){
	printf("start in main function.");

	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("print in main function:num= %d\n",num);
	return 0;
}

条件变量

条件变量是一种相对复杂的线程同步方法。
条件变量允许线程睡眠,直到满足某种条件。
当满足条件时,可以向该线程信号,通知唤醒。

在生产者—消费者模型中,
缓冲区小于等于0时,不允许消费者消费,消费者必须等待;
缓冲区满时,不允许生产者往缓冲区生产,生产者必须等待。
当生产者生产一个产品时,唤醒可能等待的消费者;
当消费者消费一个产品时,唤醒可能等待的生产者。
条件变量就是实现唤醒操作

C的API为:pthread_cond_t,需要配合互斥量使用。

// 条件变量的例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//临界资源
int MAX_BUF=100;
int num=0;
//生产者
void *producer(void*){
	while(true){
	    pthread_mutex_lock(&mutex);
		while(num>=MAX_BUF){
			//等待
			pthread_cond_wait(&cond,&mutex);
			printf("缓冲区满了,等待消费者消费...\n");
		}
		num+=1;
		printf("生产一个产品,当前产品数量为:%d\n",num);
		sleep(1);
		pthread_cond_signal(&cond);
		printf("通知消费者...\n");
		pthread_mutex_unlock(&mutex);
	}
}
//消费者
void *consumer(void*){
	while(true){
		while(num<=0){
			//等待
			pthread_cond_wait(&cond,&mutex);
			printf("缓冲区空了,等待生产者生产...\n");
		}
		num-=1;
		printf("消费一个产品,当前产品数量为:%d\n",num);
		sleep(1);
		pthread_cond_signal(&cond);
		printf("通知生产者...\n");
		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,&consumer,NULL);
	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);
	printf("print in main function:num= %d\n",num);
	return 0;
}

线程同步方法总结

互斥锁、自旋锁、读写锁
在这里插入图片描述
条件变量
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值