Linux练习_线程练习_读者写者问题

Posted Leslie X徐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux练习_线程练习_读者写者问题相关的知识,希望对你有一定的参考价值。

经典线程同步案例 读者写者问题

案例介绍

在这里插入图片描述

  1. 进程:
  • 写者进程——负责写入数据
  • 读者进程——读取数据
  1. 分析:
  • 当写者进程还没写完数据之前,读者只能等待阻塞,当写者写完以后,通知读者可以进行读取数据。
  • 当读者读完数据后,反过来去通知写者继续写入数据
  1. 框图在这里插入图片描述

  2. 代码:

/*
 * 读者写者问题
 * 轮流写入读取100次,写一个读一个
 * 
 * */

#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

//共享资源
typedef struct
{
	int 								value;
	//读者条件变量和互斥锁
	pthread_cond_t 		rc;
	pthread_mutex_t 	rm;
	int 								r_wait;  //判断读者线程条件
	//写者条件变量和互斥锁
	pthread_cond_t 		wc;
	pthread_mutex_t 	wm;
	int 								w_wait;  //判断写者线程条件
	
}Storage,*pStorage;

/*写入函数*/
void set_data(pStorage s, int value)
{
	s->value = value;
}
/*读取函数*/
int get_data(pStorage s)
{
	return s->value;
}

/*写者线程执行的线程运行函数*/
void* set_th(void* arg)
{
	pStorage s = (pStorage)arg;
	int i=1;
	//循环100次
	for(;i<=10;i++){
		//写入数据并打印信息
		set_data(s, i+100);
		printf("0x%lx(%-5d) write data: %d\\n", pthread_self(), i, i+100);
		
		pthread_mutex_lock(&s->rm);
		//判断读者线程是否准备好
		while(!s->r_wait){
		//循环,先解锁,让读者线程执行读取数据,再加锁判断条件是否满足
			pthread_mutex_unlock(&s->rm);
			sleep(1); //睡眠时,跳至读者线程s->r_wait = 1;前
			pthread_mutex_lock(&s->rm);
		}
		//读者条件清0
		s->r_wait = 0;
		pthread_mutex_unlock(&s->rm);
		//唤醒读取线程
		pthread_cond_broadcast(&s->rc); //跳至读者线程pthread_cond_wait(&s->rc, &s->rm); 下面
		
		/*写者线程等待阻塞
		*等待读者读取完数据后通知唤醒它
		*然后继续写入数据
		*/
		pthread_mutex_lock(&s->wm);
		s->w_wait = 1;
		pthread_cond_wait(&s->wc, &s->wm); //跳至判断s->w_wait循环体
		pthread_mutex_unlock(&s->wm);
	}
	
	return (void*)0;
}

/*读者线程执行的线程运行函数*/
void* get_th(void* arg)
{
	pStorage s = (pStorage)arg;
	int i=1;
	//循环100次
	for(;i<=10;i++){
		pthread_mutex_lock(&s->rm);
		//读者条件置1, 让写者执行写入数据
		s->r_wait = 1;
		//进入等待队列,等待唤醒
		pthread_cond_wait(&s->rc, &s->rm); //跳至写者线程判断s->r_wait循环体
		//解锁wait中的lock
		pthread_mutex_unlock(&s->rm); 
		
		//读取数据并输出
		int value = get_data(s); //资源被锁住时函数可以读取到数据吗?
		printf("0x%lx(%-5d) read data: %d\\n", pthread_self(), i, value);
		
		pthread_mutex_lock(&s->wm);
		//判断写者线程是否准备好
		while(!s->w_wait){
			pthread_mutex_unlock(&s->wm);
			sleep(1); //跳至写者线程s->w_wait = 1;处
			pthread_mutex_lock(&s->wm);
		}
		s->w_wait = 0;
		pthread_mutex_unlock(&s->wm);
		pthread_cond_broadcast(&s->wc); //跳至写者线程pthread_cond_wait(&s->wc, &s->wm);下面
		
	}
	
	return (void*)0;
}

/*主函数*/
int main(void)
{
	int err;
	pthread_t  rth, wth;
	Storage s;
	s.r_wait = 0;
	s.w_wait = 0;
	
	pthread_mutex_init(&s.rm, NULL);
	pthread_mutex_init(&s.wm, NULL);
	pthread_cond_init(&s.rc, NULL);
	pthread_cond_init(&s.wc, NULL);
	
	//创建一个读者线程和写者线程
	err = pthread_create(&rth, NULL,get_th, (void*)&s);
	if(err)perror("pthread create error");
	
	err = pthread_create(&wth, NULL,set_th, (void*)&s);
	if(err)perror("pthread create error");
	
	pthread_join(rth,NULL);
	pthread_join(wth,NULL);
	
	pthread_mutex_destroy(&s.rm);
	pthread_mutex_destroy(&s.wm);
	pthread_cond_destroy(&s.rc);
	pthread_cond_destroy(&s.wc);
	
	return 0;
}

  1. 输出
0xb6559460(1    ) write data: 101
0xb6d5a460(1    ) read data: 101
0xb6559460(2    ) write data: 102
0xb6d5a460(2    ) read data: 102
0xb6559460(3    ) write data: 103
0xb6d5a460(3    ) read data: 103
0xb6559460(4    ) write data: 104
0xb6d5a460(4    ) read data: 104
0xb6559460(5    ) write data: 105
0xb6d5a460(5    ) read data: 105
0xb6559460(6    ) write data: 106
0xb6d5a460(6    ) read data: 106
0xb6559460(7    ) write data: 107
0xb6d5a460(7    ) read data: 107
0xb6559460(8    ) write data: 108
0xb6d5a460(8    ) read data: 108
0xb6559460(9    ) write data: 109
0xb6d5a460(9    ) read data: 109
0xb6559460(10   ) write data: 110
0xb6d5a460(10   ) read data: 110


以上是关于Linux练习_线程练习_读者写者问题的主要内容,如果未能解决你的问题,请参考以下文章

Linux多线程_(线程池,单例模式,读者写者问题,自旋锁)

Linux练习_线程练习

LINUX多线程(线程池,单例模式,线程安全,读者写者模型)

用信号量和读写锁解决读者写者问题

C++ 多线程学习笔记:读者-写者问题模拟

Linux线程池 | 线程安全的单例模式 | STL智能指针与线程安全 | 读者写者问题