linux系统编程--线程同步

1:概念

1.1来源:资源竞争

#define MAX 100
int number;
void *funcA(void* arg){
	int i;
	for(i=0;i<MAX ; ++i){
		int cur=number;
		cur++;
		number=cur;
		printf("pthread A,ID=%lu  number=%d  \n",pthread_self(),number);
		usleep(10);
	}
	return NULL;

}

void *funcB(void* arg){
	int i;
	for(i=0;i<MAX ; ++i){
		int cur=number;
		cur++;
		number=cur;
		printf("pthread B,ID=%lu  number=%d  \n",pthread_self(),number);
		usleep(10);
	}
	return NULL;

}
int main(){
	pthread_t p1,p2;

	//创建两个子进程
	pthread_create(&p1,NULL,funcA,NULL);
	pthread_create(&p2,NULL,funcB,NULL);
	

	pthread_join(p1,NULL);
	pthread_join(p2,NULL);
		

return 0;
}

1.2思想

在这里插入图片描述

2互斥量

  • 互斥锁类型:pthread_mutex
  • 特点:保证多个线程串行的访问共享数据
  • 缺点:效率低

2.0互斥锁使用步骤

  • 创建锁:pthread_mutex_t mutex
  • 初始化:pthread_mutex_init(&mutex, NULL)==mutex=1(相当于有一把锁可以用)
  • 寻找共享资源:
    • 在操作共享资源代码之前加锁int pthread_mutex_lock(pthread_t *mute)–mutex=0
    • 在操作共享资源代码之后解锁int pthread_mutex_unlock(pthread_t *mute)–mutex=1

2.1分类:

分类实现特点
静态分配互斥量pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;简单
动态分配互斥量pthread_mutex_init(&mutex, NULL);pthread_mutex_destroy(&mutex);可以设置更多的选项

2.1加锁 int pthread_mutex_lock(pthread_t *mutex)

  • mutex没有被上锁,当前线程会将这把锁给锁上
  • 如果加锁的时候发现mutex锁已经被锁上了,线程就一直会阻塞在这个位置
  • 锁被打开的时候才会取消阻塞,而阻塞的时调用这个函数的线程

2.2尝试加锁 int pthread_mutex_trylock(pthread_t *mutex)

  • 判断这把锁是不是锁上了
    • 如果没锁上,当前线程会给这把锁锁上
    • 如果锁上了,不会阻塞,返回值
  • 返回值:成功:0 失败:错误号

2.4解锁 int pthread_mutex_unlock(pthread_t *mutex)

int number;
//创建一把互斥锁
pthread_mutex_t mutex;
void *funcA(void* arg){
	//加锁
	pthread_mutex_lock(&mutex);
	int i;
	for(i=0;i<MAX ; ++i){
		int cur=number;
		cur++;
		number=cur;
		printf("pthread A,ID=%lu  number=%d  \n",pthread_self(),number);
		usleep(10);
	}
	//解锁
	pthread_mutex_unlock(&mutex);
	return NULL;

}

void *funcB(void* arg){
	//加锁
	pthread_mutex_lock(&mutex);
	int i;
	for(i=0;i<MAX ; ++i){
		int cur=number;
		cur++;
		number=cur;
		printf("pthread B,ID=%lu  number=%d  \n",pthread_self(),number);
		usleep(10);
	}
	//解锁
	pthread_mutex_unlock(&mutex);
	return NULL;

}
int main(){
	pthread_t p1,p2;
	//初始化
	pthread_mutex_init(&mutex,NULL);

	//创建两个子进程
	pthread_create(&p1,NULL,funcA,NULL);
	pthread_create(&p2,NULL,funcB,NULL);
	

	pthread_join(p1,NULL);
	pthread_join(p2,NULL);
		
	//销毁互斥锁
	pthread_mutex_destroy(&mutex);
return 0;
}

3死锁

3.1造成死锁的原因

  • 自己锁自己
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex);
	int i;
	for(i=0;i<MAX ; ++i){
		int cur=number;
		cur++;
		number=cur;
		printf("pthread A,ID=%lu  number=%d  \n",pthread_self(),number);
		usleep(10);
	}
	//解锁
	pthread_mutex_unlock(&mutex);
  • 多个线程
    在这里插入图片描述
  • 互斥条件
  • 请求和保持条件
  • 不可剥夺条件
  • 环路等待条件

3.2结果方案

  • 让现场按照一定的顺序去访问共享资源
  • 访问其他锁的时候,先将自己的锁解开
  • trylock()

4读写锁

4.1概念

  • 读写锁是一把锁: pthread_rwlock_t lock;

4.2读写锁的类型

  • 读锁->对内存做读操作
  • 写锁->对内存做写操作

4.3特点:共享独占

  • 读取锁(共享)-并行处理
  • 写入锁(独占)
  • 读写不能同时
  • 写的优先级比较高

4.4读写锁场景练习

  • 线程A加写锁成功,线程B请求读锁
    • 线程B阻塞
  • 线程A持有读锁,线程B请求写锁
    • 线程B阻塞
  • 线程A持有读锁,线程B请求读锁
    • 线程B加锁成功
  • 线程A持有读锁,然后线程B请求写锁,然后线程C请求读锁
    • B阻塞 C阻塞(因为写操作优先级高)
    • A解索,B线程加锁成功 C继续阻塞
  • 线程A持有写锁,然后线程B请读锁,然后线程C请求写锁
    • B阻塞 C阻塞
    • A解锁 C加锁成功 B继续阻塞
    • C解锁 B加锁成功

4.5 使用场景

  • 互斥锁:读写串行
  • 程序中的读操作大于写操作的时候

4.6主要操作函数

  • 初始化
    • pthread_rwlock_init(&rwlock, NULL);
  • 销毁
    • pthread_rwlock_destroy(&rwlock);
  • 读取锁
    • int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
      • 阻塞:之前对这把锁加的写锁的操作
    • int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
      • 加锁成功:0
      • 失败:错误号
  • 写入锁
    • int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    • int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
  • 解锁
    • int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)。

4.7练习

int number=0;
pthread_rwlock_t lock;
void* write_func(void *arg){
	//循环写
	while(1){
		//加写锁
		pthread_rwlock_wrlock(&lock);
		number++;
		printf("==write: %lu, %d\n",pthread_self(),number);
		pthread_rwlock_unlock(&lock);
		usleep(500);
	}
	return NULL;

}
void* read_func(void *arg){
	while(1){
		pthread_rwlock_rdlock(&lock);
		printf("==read: %lu, %d\n",pthread_self(),number);
		pthread_rwlock_unlock(&lock);
		usleep(500);
	}
	return NULL;

}
int main(){
	int i;
	//初始化读写锁
	pthread_rwlock_init(&lock,NULL);
	pthread_t p[8];
	//创建3个写线程
	for(i=0;i<3;i++){
		pthread_create(&p[i],NULL,write_func,NULL);
	}
	//创建5个读线程
	for(i=3;i<8;i++){
		pthread_create(&p[i],NULL,read_func,NULL);
	}
	//阻塞回收子线程的pcb
	for(i=0;i<8;i++){
		pthread_join(p[i],NULL);
	}
	pthread_rwlock_destroy(&lock);
return 0;
}

5条件变量

5.1概念

  • 本质:不是锁,只是一组函数 ,但是这个函数(条件变量)能够阻塞线程
  • 如果要达到线程同步:使用条件变量+互斥锁
    • 互斥量:保护一块共享资源
    • 条件变量:引起阻塞

5.2条件变量的两个动作

  • 条件不满足时:阻塞线程
  • 条件满足时:通知阻塞阻塞线程开始工作

5.3条件变量的类型

pthread_cond_t cond;

5.4 操作函数

  • 初始化:pthread_cond_init(pthread_cond_t *cond, NULL);

  • 销毁pthread_cond_destroy(pthread_cond_t * cond);

  • 条件等待 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)

    • 阻塞线程
    • 将线程开始阻塞,将已经上锁的互斥锁解锁
    • 该线程解除阻塞,会对解锁的互斥锁加锁
  • 计时等待 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)

    • 绝对时间:在到达绝对时间后,阻塞函数将自动解除阻塞,不再阻塞线程
    • 返回值 : ETIMEDOUT 超时结束等待

正数| 错误码

  • 单个激活 int pthread_cond_signal(pthread_cond_t *cond)
    • 返回值
返回值含义
0成功
正数错误码
  • 全部激活 int pthread_cond_broadcast(pthread_cond_t *cond)
    • 返回值
返回值含义
0成功

5.5流程

void* produce(void* arg){
	typedef struct{
pthread_mutex_t mutex;
pthread_cond_t cond;
int count;
bool condition;
}Data;
void * child(void * arg){
	Data pdata=(Data *)arg;
	for(;;){ 
		pthread_mutex_lock(&mutex);
		printf("child enter \n");
		++pdata->count;
		printf("count =%d\n",pdata->count);
		sleep(1);
		if(count%3==0){
			condition=true;
			pthread_cond_signal(&pdata->cond);
			
		}
		pthread_mutex_unlock(&pdata->mutex);
		printf("child leave\n");
		usleep(10);
	}

}
void parent(void *arg){
	Data * pdata=(Data *)arg;
	for(;;){
		pthread_mutex_lock(&pdata->mutex);\
uh
		printf("parent enter\n");
		while(!pdata->condition){
			printf("wait single\n");
			pthread_cond_wait(&pdata->cond,&pdata->mutex);
		}	
		pdata->condition=false;
		printf("recieve single\n");
		pthread_mutex_unlock(&pdata->mutex);
		printf("parent leave\n");
	}

}


int main(){
	Data data
	pthread_mutex_init(&data,mutex,NULL);
	pthread_cond_init(&data,cond,NULL);
	data.cond=0;
	data.condition=false;
	
	ty

}
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值