指路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原语
- 先给互斥量mutex上锁。
- 如果资源数小于等于0,则等待,当前条件变量进入阻塞态。
- 否则资源数减一,解锁。
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: 使用信号量解决生产者、计算者、消费者问题
原理在这!
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;
}