操作系统笔记《7》-------生产者、消费者问题 。读者、写者问题 程序实现
(2011-09-23 21:28:12)
转载▼
生产者------消费者问题
分析:
该问题的基本工作模式为:如果缓冲区为空则消费者不能取;如果缓冲区为满则生产者不可以继续生产。
如果缓冲区曼,需要唤醒消费者;如果缓冲区为空则需要唤醒生产者
N个缓冲区;
如果只有一个信号量empty时,则:empty = N,in表示生产者放入缓冲区的商品的个数、out表示消费者取出
商品个数.in、out为共享变量。因此为了防止多个进程同时修改它们,将对他们的操作放在PV操作中。
Producer:
p(empty) //如果empty==0,则生产者进程自我阻塞。
p(mutex)
in:=in+1;
v(mutex)
Consumer:
v(empty)
p(mutex)
out:=out+1;
v(mutex)
小结:以上程序缺少了唤醒操作。因此引入多个信号量。用于唤醒阻塞的进程。
Producer:
p(empty) //如果empty==0,则生产者进程自我阻塞。
p(mutex)
in:=in+1 mod N;
v(mutex)
v(full)
Consumer:
p(full)
p(mutex)
out:=out+1 mod N;
v(mutex)
v(empty)
对于in、out取余的原因是为了用于循环。
实现程序:(锁和PV信号量)
文件:local.c
#ifndef _LOCAL_H
#define _LOCAL_H
#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/sem.h>
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
typedef struct MES{
int num;
int sem1[5];//该程序只使用了两个信号集
}MES;
#define BUFF 3
pthread_mutex_t mutex;
struct sembuf sbuf1={0,-1,IPC_NOWAIT};
struct sembuf sbuf2={0,1,IPC_NOWAIT};
//信号在信号集中的索引、操作类型(释放或归还)、是否阻塞
void *Producer_pthread(void *mes);
void *Consumer_pthread(void *mes);
int create_semaphore(char * path, int number, char c,union semun* sem);
//创建了两个信号量集,empty为第一个、full为第二个
#endif
文件: producer_constum.c
#include"local.h"
int create_semaphore(char * path, int number, char c,union semun* sem)
{
//如果number>0,表示empty信号量。
//如果number = 0,表示full信号量。
key_t key;
int semid;
if((key = ftok(path,c))==-1) {
perror("ftok error\n");
return -1;
}
if((semid= semget(key,1,IPC_CREAT|0666))==-1){
perror("segmet error\n");
return -1;
}
sem->val= number;
if(semctl(semid,0,SETVAL,sem)==-1){
perror("semctl error\n");
return -1;
}
return semid;
}
void* Consumer_pthread(void *mes)
{
int i =0;
while(i<10) {
semop(((MES*)mes)->sem1[1],&sbuf1,1);
pthread_mutex_lock(&mutex);
sleep(1);
printf("cumsumer: out = %d\n",((MES*)mes)->num+1);
((MES*)mes)->num = (((MES*)mes)->num+1)%BUFF;
pthread_mutex_unlock(&mutex);
semop(((MES*)mes)->sem1[0],&sbuf2,1);
i++;
sleep(1);
}
return NULL;
}
void* Producer_pthread(void *mes)
{
int i=0;
while(i<10) {
semop(((MES*)mes)->sem1[0],&sbuf1,1);
pthread_mutex_lock(&mutex);
printf("producer: in = %d\n",((MES*)mes)->num+1);
sleep(1);
((MES*)mes)->num =(((MES*)mes)->num+1)%BUFF;
pthread_mutex_unlock(&mutex);
sleep(1);
printf("wakeup consumer\n");
semop(((MES*)mes)->sem1[1],&sbuf2,1);
i++;
}
return NULL;
}
int main()
{
pthread_t produce , consume;
MES mes1,mes2;
union semun semopts1,semopts2 ;
pthread_mutex_init(&mutex,NULL);//建立具有默认值属性的
mes1.num= 0;
mes1.sem1[0]=create_semaphore(".",BUFF, 's',&semopts1);
mes1.sem1[1]=create_semaphore(".",0, 'k',&semopts2);
mes2 = mes1;
if(pthread_create(&produce,NULL,Producer_pthread,(void*)&mes1)==-1)
printf("produce ceate fail\n");
if(pthread_create(&consume,NULL,Consumer_pthread,(void*)&mes2)==-1)
printf("consume create fail\n");
pthread_join(produce,NULL);
pthread_join(consume,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
问题二
读者-----------写者问题(以缓冲区为媒介,实现读者和写者的交互)
分析:
该问题的工作原则:如果缓冲区为空时,读者不能访问缓冲区并且需要唤醒写者
如果缓冲区为满时,写者不能将信息写入缓冲区且需要唤醒读者
如果读者此时占有缓冲区,那么只允许读者进程访问该缓冲区
如果写者进程占有缓冲区,那么不允许其他进程访问该缓冲区(其他进程包括:
读者进程和别的写者进程)
由上面分析到需要下面的变量:
wm=1 rm = 1 counter = 0 (共享变量)
实现:
reader :
if(counter >=0)//读者进来,则阻塞写者进程
p(wm);
p(rm)
counter +=1;
v(rm)
读
p(rm)//读者读完离开
counter -=1;
v(rm)
if(count==0)
v(wm);此时无读者进程,将写者进程唤醒。让读者和写者进程同时竞争资源
write :
p(rm)
p(wm)
写
v(wm)
v(rm)
上面分析得因为写者进程和读者进程不可以并发执行,因此需要阻塞读者进程,因此会想到对
rm信号量进行pv操作,但是如果要看能否运行写者进程的大前提已经在读者进程中实现了,因为只有counter=0时,才会唤醒写者进程。
只需要:
p(wm)
写
v(wm)
代码实现(锁条件变量):
local_cond.h文件
#ifndef _LOCAL_COND_H
#define _LOCAL_COND_H
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
pthread_mutex_t rm ,wm;
pthread_cond_t cond;
void * Reader(void *counter);
void * Writer(void*arg);
#endif
reader_writer.c文件
#include"local_cond.h"
void * Reader(void * counter)
{
while(1) {
if(*((int*)counter) >=0)
pthread_mutex_lock(&wm);
pthread_mutex_lock(&rm);
pthread_cond_wait(&cond,&wm);
(*(int*)counter) +=1;
printf("reader is reading\n");
printf("Reader :=%d\n",(*(int*)counter));
pthread_mutex_unlock(&rm);
pthread_mutex_lock(&rm);
printf("reader left \n");
(*(int*)counter) -=1;
printf("Reader :=%d\n",(*(int*)counter));
pthread_cond_wait(&cond,&wm);
pthread_mutex_unlock(&rm);
if((*(int*)counter)==0)
pthread_mutex_unlock(&wm);
sleep(1);
}
return NULL;
}
void* Writer(void *arg)
{
while(1) {
pthread_mutex_lock(&wm);
pthread_cond_wait(&cond,&wm);
printf("Writer is writing\n");
pthread_mutex_unlock(&wm);
pthread_cond_signal(&cond);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t reader,writer;
int counter = 0;
pthread_mutex_init(&rm,NULL);
pthread_mutex_init(&wm,NULL);
pthread_cond_init(&cond,NULL);
pthread_create(&writer,NULL,(void*)Writer,NULL);
pthread_create(&reader,NULL,(void*)Reader,(void*)&counter);
do{
pthread_cond_signal(&cond);
}while(1);
pthread_join(writer,NULL);
pthread_join(reader,NULL);
pthread_mutex_destory(&rm);
pthread_mutex_destory(&wm);
pthread_cond_destory(&cond);
return 0;
}
分享: 分享到新浪Qing
喜欢
阅读┊ 评论 ┊ 收藏 ┊转载┊ 喜欢▼ ┊打印┊举报
加载中,请稍候......
前一篇:操作系统笔记《6》-----进程间的同步和通信
后一篇:操作系统笔记《7》-------哲学家吃饭问题