操作系统实践 job8

目录

job8/pc.c: 使用条件变量解决生产者、计算者、消费者问题

前置知识点

进程互斥

条件变量

思路

生产者线程与消费者线程需要同步

完成生产者线程的框架

完成计算者框架

完成消费者框架

总体代码

结果:

job8/pp.c: 使用条件变量实现 ping-pong 问题

思路

代码


job8/pc.c: 使用条件变量解决生产者、计算者、消费者问题

+ 系统中有3个线程:生产者、计算者、消费者
+ 系统中有2个容量为4的缓冲区:buffer1、buffer2
+ 生产者
  - 生产'a'、'b'、'c'、‘d'、'e'、'f'、'g'、'h'八个字符
  - 放入到buffer1
  - 打印生产的字符
+ 计算者
  - 从buffer1取出字符
  - 将小写字符转换为大写字符,按照 input:OUTPUT 的格式打印
  - 放入到buffer2
+ 消费者
  - 从buffer2取出字符
  - 打印取出的字符
+ 程序输出结果(实际输出结果是交织的)
a
b
c
...
    a:A
    b:B
    c:C
    ...
        A
        B
        C
        ...

前置知识点

进程互斥

初始化互斥量:

加锁解锁:

条件变量

初始化:

等待:

 唤醒线程:

思路

跟老师的模板也是如出一辙,采用buffer1和buffer2两个缓冲区,因此,mutex互斥量也需要俩,同时wait_full_buffer和wait_empty_buffer也各需要俩。

生产者线程与消费者线程需要同步

  • 生产者生产ITEM_COUNT个数据
  • 消费者消费ITEM_COUNT个数据

生产者生产数据过快

  • 导致缓冲区为满
  • 生产者需要等待条件变量wait_empty_buffer

消费者消费数据过快

  • 导致缓冲区为空
  • 消费者需要等待条件变量wait_full_buffer
#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
int in1,in2;
int out1,out2;

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
pthread_cond_t wait_empty_buffer1;
pthread_cond_t wait_full_buffer1;
pthread_cond_t wait_empty_buffer2;
pthread_cond_t wait_full_buffer2;


#define ITEM_COUNT (CAPACITY*2)
  • 使用条件变量实现生产者与消费者问题
    • 存在一个共享缓冲区
    • 生产者线程向共享缓冲区1写数据
    • 计算者从共享缓冲区1读数据,并向共享缓冲区2写数据
    • 消费者线程从共享缓冲区2读数据
  • 使用长度为4的数组表示共享缓冲区
  • 变量out为共享缓冲去的读指针;变量in为共享缓冲去的写指针
  • in指针和out指针相同时,缓冲区为空;in指针和out指针相邻时,缓冲区为满

    • in指针指向数组最后一项元素时

    • in+1越界

    • 通过求模保证in指针处于数组边界内

注意我的in和out是全局变量,因此传参的时候需要传地址,否则无法改变他们的值。

int buffer_is_empty(int *in,int *out)
{
	return *in==*out;
}
int buffer_is_full(int *in,int *out)
{
	return (*in+1)%CAPACITY==*out;
}
  • get_item获取out指针指向的元素,同时,移动out指针指向下一项
  • put_item将元素放置在in指针指向的位置,同时,移动in指针指向下一项
  • type区分buffer
int get_item(int *out,int type)
{
	int item;
	if(type==1)item=buffer1[*out];
	else item=buffer2[*out];
	*out=(*out+1)%CAPACITY;
	return item;
}
void put_item(int item,int *in,int type)
{
	if(type==1)buffer1[*in]=item;
	else buffer2[*in]=item;
	*in=(*in+1)%CAPACITY;
}

完成生产者线程的框架

生产者生产ITEM_COUNT个数据

  • 如果buffer_is_full为真,缓冲区为满,生产者需要一个空的缓冲区。生产者等待条件变量wait_empty_buffer。
  • 生产者生产一个数据,释放一个满缓冲区,唤醒等待满缓冲区的消费者。
void *produce(void *arg)
{
	int i,item,type=1;
	for(i=0;i<ITEM_COUNT;i++)
	{
		pthread_mutex_lock(&mutex1);
		while(buffer_is_full(&in1,&out1))
			pthread_cond_wait(&wait_empty_buffer1,&mutex1);
		item='a'+i;
		put_item(item,&in1,type);
		printf("produce item: %c\n",item);

		pthread_cond_signal(&wait_full_buffer1);
		pthread_mutex_unlock(&mutex1);
	}
	return NULL;
}

完成计算者框架

  • 前半部分参考消费者,后半部分参考生产者。、
  • 需要俩互斥量,因为是两个不同的临界区。
  • 小写-32是大写
void *compute(void *arg)
{
	//printf("enter compute fun");
	int i,item,type;
	for(i=0;i<ITEM_COUNT;i++)
	{
		type=1;
		pthread_mutex_lock(&mutex1);
		while(buffer_is_empty(&in1,&out1))
			pthread_cond_wait(&wait_full_buffer1,&mutex1);
		item=get_item(&out1,type);
		//printf("	compute item: %c:",item);
		pthread_cond_signal(&wait_empty_buffer1);
		pthread_mutex_unlock(&mutex1);
		
		type=2;
		pthread_mutex_lock(&mutex2);
		while(buffer_is_full(&in2,&out2))
			pthread_cond_wait(&wait_empty_buffer2,&mutex2);
		item-=32;
		put_item(item,&in2,type);
		printf("	compute item: %c:%c\n",item+32,item);
		pthread_cond_signal(&wait_full_buffer2);
		pthread_mutex_unlock(&mutex2);
	}
}

完成消费者框架

  • 如果buffer_is_empty为真,缓冲区为空,消费者需要一个满的缓冲区,消费者等待条件变量wait_full_buffer。

  • 消费者取走一个数据,释放一个空缓冲区,唤醒等待空缓冲区的计算者。

void *consume(void *arg)
{
	int i,item,type=2;
	for(i=0;i<ITEM_COUNT;i++)
	{
		pthread_mutex_lock(&mutex2);
		while(buffer_is_empty(&in2,&out2))
				pthread_cond_wait(&wait_full_buffer2,&mutex2);
                item=get_item(&out2,type);
                printf("        	consume item: %c\n",item);
                pthread_cond_signal(&wait_empty_buffer2);
		pthread_mutex_unlock(&mutex2);
	}
}

总体代码

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

#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
int in1,in2;
int out1,out2;
int buffer_is_empty(int *in,int *out)
{
	return *in==*out;
}
int buffer_is_full(int *in,int *out)
{
	return (*in+1)%CAPACITY==*out;
}
int get_item(int *out,int type)
{
	int item;
	if(type==1)item=buffer1[*out];
	else item=buffer2[*out];
	*out=(*out+1)%CAPACITY;
	return item;
}
void put_item(int item,int *in,int type)
{
	if(type==1)buffer1[*in]=item;
	else buffer2[*in]=item;
	*in=(*in+1)%CAPACITY;
}

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
pthread_cond_t wait_empty_buffer1;
pthread_cond_t wait_full_buffer1;
pthread_cond_t wait_empty_buffer2;
pthread_cond_t wait_full_buffer2;


#define ITEM_COUNT (CAPACITY*2)

void *produce(void *arg)
{
	int i,item,type=1;
	for(i=0;i<ITEM_COUNT;i++)
	{
		pthread_mutex_lock(&mutex1);
		while(buffer_is_full(&in1,&out1))
			pthread_cond_wait(&wait_empty_buffer1,&mutex1);
		item='a'+i;
		put_item(item,&in1,type);
		printf("produce item: %c\n",item);

		pthread_cond_signal(&wait_full_buffer1);
		pthread_mutex_unlock(&mutex1);
	}
	return NULL;
}

void *compute(void *arg)
{
	//printf("enter compute fun");
	int i,item,type;
	for(i=0;i<ITEM_COUNT;i++)
	{
		type=1;
		pthread_mutex_lock(&mutex1);
		while(buffer_is_empty(&in1,&out1))
			pthread_cond_wait(&wait_full_buffer1,&mutex1);
		item=get_item(&out1,type);
		//printf("	compute item: %c:",item);
		pthread_cond_signal(&wait_empty_buffer1);
		pthread_mutex_unlock(&mutex1);
		
		type=2;
		pthread_mutex_lock(&mutex2);
		while(buffer_is_full(&in2,&out2))
			pthread_cond_wait(&wait_empty_buffer2,&mutex2);
		item-=32;
		put_item(item,&in2,type);
		printf("	compute item: %c:%c\n",item+32,item);
		pthread_cond_signal(&wait_full_buffer2);
		pthread_mutex_unlock(&mutex2);
	}
}
void *consume(void *arg)
{
	int i,item,type=2;
	for(i=0;i<ITEM_COUNT;i++)
	{
		pthread_mutex_lock(&mutex2);
		while(buffer_is_empty(&in2,&out2))
				pthread_cond_wait(&wait_full_buffer2,&mutex2);
                item=get_item(&out2,type);
                printf("        	consume item: %c\n",item);
                pthread_cond_signal(&wait_empty_buffer2);
		pthread_mutex_unlock(&mutex2);
	}
}

int main()
{
	pthread_t compute_tid;
	pthread_t consume_tid;

 	pthread_mutex_init(&mutex1, NULL);
 	pthread_mutex_init(&mutex2, NULL);
    	pthread_cond_init(&wait_empty_buffer1, NULL);
    	pthread_cond_init(&wait_full_buffer1, NULL);
	pthread_cond_init(&wait_empty_buffer2, NULL);
        pthread_cond_init(&wait_full_buffer2, NULL);

	pthread_create(&compute_tid, NULL, compute, NULL);
    	pthread_create(&consume_tid, NULL, consume, NULL);
    	produce(NULL); 
    	pthread_join(consume_tid, NULL);
	pthread_join(compute_tid, NULL);
    	return 0;
}

结果:

job8/pp.c: 使用条件变量实现 ping-pong 问题

+ 系统中有2个线程:ping 线程和 pong 线程
+ ping 线程先执行
+ ping 线程执行流程如下
  1. 打印输出 ping
  2. 等待 pong 线程输出
  3. 执行第 1 步
+ pong 线程执行流程如下
  1. 打印输出 pong
  2. 等待 ping 线程输出
  3. 执行第 1 步
+ 程序输出结果
  ping
  pong
  ping
  pong
  ...

思路

 定义p作为状态量,p=1表示ping线程运行,p=0表示pong线程运行。要满足互斥,就要设置一个互斥量,和俩等待条件变量。当p=0即pong在运行时,进行等待pong。然后输出ping,将p设为1,表示pong即将进入临界区。释放一个等待ping的缓冲区,并唤醒pong。

代码

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
int p=1;
#define COUNT 10
pthread_mutex_t mutex;
pthread_cond_t wait_ping;
pthread_cond_t wait_pong;

void *ping(void *arg)
{
	int i=COUNT;
	while(i--){

		pthread_mutex_lock(&mutex);
		while(p==0)
			pthread_cond_wait(&wait_pong,&mutex);
		printf("ping\n");
		p=0;
		pthread_cond_signal(&wait_ping);
		pthread_mutex_unlock(&mutex);
	}
	return NULL;
}
void *pong(void *arg)
{
	int i=COUNT;
	while(i--)
	{
		
		pthread_mutex_lock(&mutex);
        	while(p==1)
        	        pthread_cond_wait(&wait_ping,&mutex);
        	printf("pong\n");
        	p=1;
        	pthread_cond_signal(&wait_pong);
        	pthread_mutex_unlock(&mutex);
	}
	return NULL;
}
int main()
{
	pthread_t pong_tid;

	pthread_mutex_init(&mutex,NULL);
	pthread_cond_init(&wait_ping,NULL);
	pthread_cond_init(&wait_pong,NULL);
	
	pthread_create(&pong_tid,NULL,pong,NULL);
	ping(NULL);
	pthread_join(pong_tid,NULL);
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值