操作系统实践 job9 基于信号量实现线程同步

指路job8:操作系统实践 job8_LarsGyonX的博客-CSDN博客

采取了记录型信号量来模拟。

理论课上学的部分。

关于同步和互斥的概念

互斥是某一资源只允许一个访问者对他访问,访问是无序的。
同步是在互斥的基础上,让各并发进程有序推进。

信号量数据结构

剩余资源数是value,mutex和cond是等待进程。

typedef struct{
	int value;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
}sema_t;

信号量的初始化

初始化剩余资源数,mutex和cond;

void sema_init(sema_t *sema,int value)
{
	sema->value=value;
	pthread_mutex_init(&sema->mutex,NULL);
	pthread_cond_init(&sema->cond,NULL);
}

wait原语

  1. 先给互斥量mutex上锁。
  2. 如果资源数小于等于0,则等待,当前条件变量进入阻塞态。
  3. 否则资源数减一,解锁。
void sema_wait(sema_t *sema)
{
	pthread_mutex_lock(&sema->mutex);
	while(sema->value<=0)
	{
		pthread_cond_wait(&sema->cond,&sema->mutex);
	}
	sema->value--;
	pthread_mutex_unlock(&sema->mutex);
}

 signal原语

  • 先给互斥量上锁
  • 释放一个资源,资源数++;
  • 释放条件变量和互斥量。
void sema_signal(sema_t *sema)
{
	pthread_mutex_lock(&sema->mutex);
	++sema->value;
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}

job9/pc.c: 使用信号量解决生产者、计算者、消费者问题

原理在这!

王道计算机考研 操作系统_哔哩哔哩_bilibili

2.3.6 操作系统之进程同步与互斥经典问题(生产者-消费者问题、多生产者-多消费者问题、吸烟者问题、读者-写者问题、哲学家进餐问题)_BitHachi的博客-CSDN博客

同步关系: 

  • 生产者、计算者共享一个初始为空、大小为n的缓冲区1。
  • 计算者、消费者共享一个初始为空、大小为n的缓冲区2。
  • 只有缓冲区没满时,生产者(计算者)才能把产品放入缓冲区,否则必须等待。
  • 只有缓冲区不空时,消费者(计算者)才能从中取出产品,否则必须等待。

互斥关系:

  • 缓冲区是临界资源,各进程必须互斥地访问。

初始化信号量

    sema_init(&mutex_sema1,1);
	sema_init(&mutex_sema2,1);
	sema_init(&empty_buffer1_sema,CAPACITY);
	sema_init(&empty_buffer2_sema,CAPACITY);
	sema_init(&full_buffer1_sema,0);
	sema_init(&full_buffer2_sema,0);

 生产者

void *produce()
{
	int i,item,type=1;
	for(i=0;i<ITEM_COUNT;i++)
	{
		sema_wait(&empty_buffer1_sema);//消耗一个空闲缓冲区
		sema_wait(&mutex_sema1);//实现互斥
		item=i+'a';
		put_item(item,&in1,type);//从临界区存数据
		printf("produce item: %c\n",item);

		sema_signal(&mutex_sema1);//互斥
		sema_signal(&full_buffer1_sema);//增加一个满缓冲区,释放一个物品
	}
}

计算者

void *compute(void *arg){
	int i,item,type;
	for(i=0;i<ITEM_COUNT;i++)
	{
		type=1;
		sema_wait(&full_buffer1_sema);//消耗一个产品
		sema_wait(&mutex_sema1);//互斥
		item=get_item(&out1,type);//从临界区buffer1取数据
		sema_signal(&mutex_sema1);//互斥
		sema_signal(&empty_buffer1_sema);//释放buffer1一个空闲区域

		type=2;
		sema_wait(&empty_buffer2_sema);//消耗一个空闲缓冲区
		sema_wait(&mutex_sema2);//互斥
		item-=32;
		put_item(item,&in2,type);//在buffer2中房数据
		printf("	compute item: %c:%c\n",item+32,item);
		sema_signal(&mutex_sema2);//互斥
		sema_signal(&full_buffer2_sema);//占用一个buffer2空闲区域,释放一个产品
	}
	return NULL;
}

消费者

void *consume(void *arg)
{
	int i,item,type=2;
	for(i=0;i<ITEM_COUNT;i++)
	{
		sema_wait(&full_buffer2_sema);//消耗一个物品,减少一个满缓冲区
		sema_wait(&mutex_sema2);//互斥

		item=get_item(&out2,type);//获取商品
		printf("		consume item: %c\n",item);
		sema_signal(&mutex_sema2);//互斥
		sema_signal(&empty_buffer2_sema);//增加一个空闲缓冲区
	}
	return NULL;
}

所有代码

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

#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
int in1,in2;
int out1,out2;
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;
}
typedef struct{
	int value;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
}sema_t;

void sema_init(sema_t *sema,int value)
{
	sema->value=value;
	pthread_mutex_init(&sema->mutex,NULL);
	pthread_cond_init(&sema->cond,NULL);
}
void sema_wait(sema_t *sema)
{
	pthread_mutex_lock(&sema->mutex);
	while(sema->value<=0)
	{
		pthread_cond_wait(&sema->cond,&sema->mutex);
	}
	sema->value--;
	pthread_mutex_unlock(&sema->mutex);
}
void sema_signal(sema_t *sema)
{
	pthread_mutex_lock(&sema->mutex);
	++sema->value;
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}
sema_t mutex_sema1;
sema_t mutex_sema2;
sema_t empty_buffer1_sema;
sema_t empty_buffer2_sema;
sema_t full_buffer1_sema;
sema_t full_buffer2_sema;

#define ITEM_COUNT (CAPACITY*2)
void *produce()
{
	int i,item,type=1;
	for(i=0;i<ITEM_COUNT;i++)
	{
		sema_wait(&empty_buffer1_sema);
		sema_wait(&mutex_sema1);
		item=i+'a';
		put_item(item,&in1,type);
		printf("produce item: %c\n",item);

		sema_signal(&mutex_sema1);
		sema_signal(&full_buffer1_sema);
	}
}
void *compute(void *arg){
	int i,item,type;
	for(i=0;i<ITEM_COUNT;i++)
	{
		type=1;
		sema_wait(&full_buffer1_sema);
		sema_wait(&mutex_sema1);
		item=get_item(&out1,type);
		sema_signal(&mutex_sema1);
		sema_signal(&empty_buffer1_sema);

		type=2;
		sema_wait(&empty_buffer2_sema);
		sema_wait(&mutex_sema2);
		item-=32;
		put_item(item,&in2,type);
		printf("	compute item: %c:%c\n",item+32,item);
		sema_signal(&mutex_sema2);
		sema_signal(&full_buffer2_sema);
	}
	return NULL;
}
		
void *consume(void *arg)
{
	int i,item,type=2;
	for(i=0;i<ITEM_COUNT;i++)
	{
		sema_wait(&full_buffer2_sema);
		sema_wait(&mutex_sema2);

		item=get_item(&out2,type);
		printf("		consume item: %c\n",item);
		sema_signal(&mutex_sema2);
		sema_signal(&empty_buffer2_sema);
	}
	return NULL;
}
int main()
{
	pthread_t consumer_tid;
	pthread_t computer_tid;
	sema_init(&mutex_sema1,1);
	sema_init(&mutex_sema2,1);
	sema_init(&empty_buffer1_sema,CAPACITY);
	sema_init(&empty_buffer2_sema,CAPACITY);
	sema_init(&full_buffer1_sema,0);
	sema_init(&full_buffer2_sema,0);

	pthread_create(&consumer_tid,NULL,consume,NULL);
	pthread_create(&computer_tid,NULL,compute,NULL);
	produce(NULL);
	pthread_join(consumer_tid, NULL);
	pthread_join(computer_tid, NULL);
    	return 0;
}

job9/pp.c: 使用信号量实现 ping-pong 问题

先ping后pong,因此需要进行同步操作。且ping是pong的前操作,前操作进行完需要进行V操作,pong为ping的后操作,后操作前需要进行P操作。但与此同时,当进行了pong以后又要进行ping,因此pong也是ping的前操作。

这里的pv操作不是需要访问临界区,而是进行状态的转化。这里将ping设为1,pong设为0。

wait原语

void sema_wait(sema_t *sema,int status)//status是下一步要执行的状态
{
	pthread_mutex_lock(&sema->mutex);
	while(sema->value!=status)//如果不是status,需要等待
	{
		pthread_cond_wait(&sema->cond,&sema->mutex);
	}
	pthread_mutex_unlock(&sema->mutex);
}

signal原语

void sema_signal(sema_t *sema,int status)
{
	pthread_mutex_lock(&sema->mutex);
	sema->value=status;//执行完操作后状态改变
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}

ping函数

void *ping(void *arg)
{
	int i=COUNT;
	while(i--)
	{
		sema_wait(&mutex_sema,1);//即将进行的操作是1(ping),如果不是ping,就等待
		printf("ping\n");
		sema_signal(&mutex_sema,0);//将状态转为0
	}
}

pong函数

//和ping大同小异
void *pong(void *arg)
{
        int i=COUNT;
        while(i--)
        {
                sema_wait(&mutex_sema,0);
                printf("pong\n");
                sema_signal(&mutex_sema,1);
        }
}

全部代码

#include<stdio.h>
#include<pthread.h>
#define COUNT 100
typedef struct{
	int value;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
}sema_t;
void sema_init(sema_t *sema,int value)
{
	sema->value=value;
	pthread_mutex_init(&sema->mutex,NULL);
	pthread_cond_init(&sema->cond,NULL);
}
void sema_wait(sema_t *sema,int status)
{
	pthread_mutex_lock(&sema->mutex);
	while(sema->value!=status)
	{
		pthread_cond_wait(&sema->cond,&sema->mutex);
	}
	pthread_mutex_unlock(&sema->mutex);
}
void sema_signal(sema_t *sema,int status)
{
	pthread_mutex_lock(&sema->mutex);
	sema->value=status;
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}
sema_t mutex_sema;
void *ping(void *arg)
{
	int i=COUNT;
	while(i--)
	{
		sema_wait(&mutex_sema,1);
		printf("ping\n");
		sema_signal(&mutex_sema,0);
	}
}
void *pong(void *arg)
{
        int i=COUNT;
        while(i--)
        {
                sema_wait(&mutex_sema,0);
                printf("pong\n");
                sema_signal(&mutex_sema,1);
        }
}

int main()
{
	pthread_t pong_tid;
	sema_init(&mutex_sema,0);
	pthread_create(&pong_tid,NULL,pong,NULL);
	ping(NULL);
	pthread_join(pong_tid,NULL);
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值