生产者和消费者 实例

7 views
Skip to first unread message

Niu Tao

unread,
Sep 24, 2008, 3:28:33 AM9/24/08
to 操作系统课程论坛
下面要演示的程序是一个关于生产者和消费者的问题。我们在操作系统中讲到进程同步的问题的时候,都会讲一些经典的例子,其中就有“生产者和消费者的问
题”。生产者和消费者的规则是生产者生产一个产品后,消费者才能消费,并且在消费者还没有消费已经生产的产品的时候,生产者是不能再进行生产的。一下的
这个例子就是演示这个生产者和消费者问题的例子:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/sem.h>
#include<linux/sched.h>
MODULE_LICENSE("Dual BSD/GPL");

struct semaphore sem_producer;/*"生产需求证",在产品没有被消费的时候不能再进行生产*/
struct semaphore sem_consumer;/*"消费证",在有产品的时候(可以获得该锁)才可以消费*/
char product[10];/*"产品"存放地*/
int exit_flags;/*生产线开启标志*/
int producer(void *product);/*生产者*/
int consumer(void *product);/*消费者*/

static int procon_init(void)
{
printk(KERN_INFO"show producer and consumer\n");
init_MUTEX(&sem_producer);/*购买"生产需求证",并且准许生产*/
init_MUTEX_LOCKED(&sem_consumer);/*购买"消费证",但不可消费*/
exit_flags=0;/*生产线可以开工*/
kernel_thread(producer,product,CLONE_KERNEL);/*启动生产者*/
kernel_thread(consumer,product,CLONE_KERNEL);/*启动消费者*/
return 0;
}
static void procon_exit(void)
{
printk(KERN_INFO"exit producer and consumer\n");
}
/*
* 生产者,负责生产十个产品
*/
int producer(void *p)
{
char *product=(char *)p;
int i;
for(i=0;i<10;i++) { /*总共生产十个产品*/
/* 查看"生产需求证",如果产品已经被消费,
* 则准许生产。否则在此等待直到需要生产
*/
down(&sem_producer);
snprintf(product,10,"product-%d",i);/*生产产品*/
printk(KERN_INFO"producer produce %s\n",product);/*生产者提示已经生产*/
up(&sem_consumer);/*为消费者发放"消费证"*/
}
exit_flags=1;/*生产完毕,关闭生产线*/
return 0;
}
/*
* 消费者,如果有产品,则消费产品
*/
int consumer(void *p)
{
char *product=(char *)p;
for(;;) {
if(exit_flags) /*如果生产工厂已经关闭,则停止消费*/
break;
/*获取"消费证",如果有产品,则可以获取,
*进行消费。否则等待直到有产品。
*/
down(&sem_consumer);
printk(KERN_INFO"consumer consume %s\n",product);/*消费者提示获得了产品
*/
memset(product,'\0',10);/*消费产品*/
up(&sem_producer);/*向生产者提出生产需求*/
}
return 0;
}
module_init(procon_init);
module_exit(procon_exit);
MODULE_AUTHOR("Niu Tao");
MODULE_DESCRIPTION("producer and consumer Module");
MODULE_ALIAS("a simplest module");


Makefile:

obj-m :=procon.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)

all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
Module.symvers .Makefile.swp


运行结果:

[ 5684.818139] show producer and consumer
[ 5684.818352] producer produce product-0
[ 5684.819746] consumer consume product-0
[ 5684.819811] producer produce product-1
[ 5684.820061] consumer consume product-1
[ 5684.820065] producer produce product-2
[ 5684.820267] consumer consume product-2
[ 5684.820271] producer produce product-3
[ 5684.820498] consumer consume product-3
[ 5684.820503] producer produce product-4
[ 5684.820822] consumer consume product-4
[ 5684.820828] producer produce product-5
[ 5684.821062] consumer consume product-5
[ 5684.821067] producer produce product-6
[ 5684.821274] consumer consume product-6
[ 5684.821279] producer produce product-7
[ 5684.821475] consumer consume product-7
[ 5684.821479] producer produce product-8
[ 5684.821681] consumer consume product-8
[ 5684.821685] producer produce product-9
[ 5684.821897] consumer consume product-9
[ 5705.169930] exit producer and consumer

陈老师

unread,
Sep 24, 2008, 10:53:52 AM9/24/08
to xiyouo...@googlegroups.com


2008/9/24 Niu Tao <niuta...@gmail.com>
这给例子很好,也很完整,注释也到位。

Niu Tao

unread,
Sep 28, 2008, 2:13:03 AM9/28/08
to xiyouo...@googlegroups.com
在我写的前一个这样的例子里,由于仓库可以存放产品的位置只有一个,所以生产者和消费者只能是生产一个,消费一个,也就是按产品的生产日期进行消费,生产早的线消费。那在现实中,往往不是这样的。比如一个仓库很大的时候,可以放很多产品,生产早的有可能被积压在下面,而后于生产迟的产品被消费。所以该程序就考虑了这一现实问题,模拟生产者和消费者的行为过程。况且在实际生产中,有可能有很多生产厂商生产同一个产品,也可能有很多个消费者消费产品,所以本程序也可以模拟这种情况(将注释掉的kernel_thread添加上就可以了)。以下是代码:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/wait.h>
#include<linux/sem.h>
#include<linux/sched.h>
#define BUFF_SIZE 10 /*仓库中有十个位置可以存放产品*/
/*
* _PRODUCE: 标识生产者的状态:
* RUNNING: 生产中
* STOPPED: 停止生产
*/
typedef enum _PRODUCE{RUNNING,STOPPED}PRODUCE;
/*
* _storage: 产品存放地
* buff : 仓库
* lock: 仓库门锁,一个时间只能允许生产者存放产品或者只允许消费者消费产品
* amount: 产品现有的个数
* state: 生产者的生产状态
* (*wait): 锁定仓库门
* (*signal): 开启仓库门
*/
struct _storage {
char buff[BUFF_SIZE][20];
struct semaphore lock;
int amount;
PRODUCE state;
void (*wait)(struct semaphore *lock);
void (*signal)(struct semaphore *lock);
};
/*
* procon_lock: 产品数量检查锁
* (*wait): 等待有产品可以消费或者是等待仓库有位置可以放产品
* (*signla): 消费产品或者存放产品返回
*/
struct procon_lock {
struct _storage *storage;
void (*wait)(struct _storage *storage);
void (*signal)(struct _storage *storage);
};

/*
* _lock: 打包各种资源
* *storage: 仓库资源
* *empty: 等待仓库有位置可以存放产品
* *full: 等待仓库里有产品可以消费
*/
struct _lock {
struct _storage *storage;
struct procon_lock *empty;
struct procon_lock *full;
};

void empty_wait(struct _storage *storage);
void empty_signal(struct _storage *storage);
void full_wait(struct _storage *storage);
void full_signal(struct _storage *storage);
int producer(void *p);
int consumer(void *p);
/*
* storage: 仓库
*/
struct _storage storage = {
.amount=0, /*初始仓库中没有产品*/
.state=RUNNING,
.wait=down,
.signal=up,
};
/*
* empty: 等待仓库有位置方产品锁
*/
struct procon_lock empty = {
.storage=&storage,
.wait=empty_wait,
.signal=empty_signal,
};
/*
* full: 等待仓库有产品可以消费锁
*/
struct procon_lock full = {
.storage=&storage,
.wait=full_wait,
.signal=full_signal,
};
/*
* lock: 打包资源,将其传递给生产者和消费者
*/
struct _lock lock = {
.storage = &storage,
.empty = &empty,
.full = &full
};

MODULE_LICENSE("Dual BSD/GPL");
/*
* procon_init: 内核模块初始化函数
*/
static int procon_init(void)
{
printk(KERN_INFO"Resolving the proceducer-consumer problem\n");
memset(storage.buff,'\0',BUFF_SIZE*20);/*清空仓库*/
init_MUTEX(&storage.lock); /*打开仓库门*/

//kernel_thread(producer,&lock,CLONE_KERNEL);
//kernel_thread(producer,&lock,CLONE_KERNEL);
kernel_thread(producer,&lock,CLONE_KERNEL); /*启动生产线,生产者开始生产产品*/
kernel_thread(consumer,&lock,CLONE_KERNEL);/*消费者开始消费产品*/
//kernel_thread(consumer,&lock,CLONE_KERNEL);

return 0;
}
/*
* procon_exit: 内核模块卸载函数
*/
static void procon_exit(void)
{
printk(KERN_INFO"Resolved the proceducer-consumer problem\n");
}


/*
* producer: 生产者,负责生产二十个产品
* @*p: 生产需要的资源
*/
int producer(void *p)
{
struct _lock *lock=(struct _lock *)p; /*解包资源*/
struct _storage *storage=lock->storage;/*获取仓库资源*/
struct procon_lock *empty=lock->empty;/*获取仓库位置探测资源*/
struct procon_lock *full=lock->full;/*获取仓库位置探测资源*/
struct task_struct *task=current;/*取得当前线程描述符*/
int i,j;

printk(KERN_INFO"%d:producer start produce
products...\n",task->pid);/*显示开始生产*/
for(i=0;i<20;i++) { /*总共生产二十个产品*/
empty->wait(empty->storage); /*如果仓库已经放满,则等待直到有位置可以放产品*/
storage->wait(&storage->lock);/*打开仓库门*/
for(j=0;j<BUFF_SIZE;j++) { /*寻找一个可以放产品的位置*/
if(!strlen(storage->buff[j]))
break;
}

snprintf(storage->buff[j],20,"%d:product-%d",task->pid,i);/*生产产品,放入仓库*/
printk(KERN_INFO"%d:producer produce
%s\n",task->pid,storage->buff[j]);/*生产者提示已经生产*/
full->signal(full->storage);/*提示消费者有产品可以消费*/
storage->signal(&storage->lock);/*关闭仓库门*/
}
storage->state=STOPPED;/*生产完毕,关闭生产线*/
printk(KERN_INFO"%d:producer exit...\n",task->pid); /*退出生产*/
return 0;
}
/*
* consumer: 消费者,如果有产品,则消费产品
* @*p: 消费需要的资源
*/
int consumer(void *p)
{
struct _lock *lock=(struct _lock *)p;
struct _storage *storage=lock->storage;
struct procon_lock *empty=lock->empty;
struct procon_lock *full=lock->full;
struct task_struct *task=current;
int i;
printk(KERN_INFO"%d:consumer start consume
products...\n",task->pid);/*提示开始消费*/
for(;;) {
/*如果仓库中已经没有产品并且生产者已经退出生产线,则停止消费*/
if(storage->amount==0&&storage->state==STOPPED){
break;
}

full->wait(full->storage); /*如果仓库门没有产品,则等待直到有产品*/
storage->wait(&storage->lock);/*打开仓库门*/
for(i=0;i<BUFF_SIZE;i++) {/*寻找一个产品*/
if(strlen(storage->buff[i]))
break;
}

printk(KERN_INFO"%d:consumer consume
%s\n",task->pid,storage->buff[i]);/*消费者提示获得了产品*/
memset(storage->buff[i],'\0',20);/*消费产品*/
empty->signal(empty->storage);/*告诉生产者仓库有位置可以放产品*/
storage->signal(&storage->lock); /*关闭仓库门*/
}
printk(KERN_INFO"%d:consumer exit...\n",task->pid);
return 0;
}
/*
* empty_wait: 等待仓库中有位置可以放产品
* @storage: 仓库
*/
void empty_wait(struct _storage *storage)
{
do {
if(storage->amount<BUFF_SIZE) /*如果仓库中有位置可以放产品,则退出等待*/
break;
schedule();/*等待仓库中有空位置*/
}while(1);
}
/*
* empty_signal: 通知生产者者仓库中有位置可以放产品
* @*storage: 仓库
*/
void empty_signal(struct _storage *storage)
{
storage->amount--; /*产品计数减一*/
}
/*
* full_wait: 等待仓库中有产品可以消费
* @*storage: 仓库
*/
void full_wait(struct _storage *storage)
{
do {
if(storage->amount>0) /*如果仓库中有产品可以消费,则返回*/
break;
schedule();/*等待有产品*/
}while(1);
}
/*
* full_signal: 通知消费者仓库中有产品可以消费
* @*storage: 仓库
*/
void full_signal(struct _storage *storage)
{
storage->amount++; /*产品计数加一*/
}

module_init(procon_init);
module_exit(procon_exit);
MODULE_AUTHOR("Niu Tao");

MODULE_DESCRIPTION("The proceducer-consumer problem");


MODULE_ALIAS("a simplest module");


Makefile:

obj-m :=procon.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)

all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions Module.symvers .Makefile.swp


程序运行结果:

[13899.280451] Resolving the proceducer-consumer problem
[13899.284977] 16104:producer start produce products...
[13899.284984] 16104:producer produce 16104:product-0
[13899.284987] 16104:producer produce 16104:product-1
[13899.284990] 16104:producer produce 16104:product-2
[13899.284992] 16104:producer produce 16104:product-3
[13899.284994] 16104:producer produce 16104:product-4
[13899.284997] 16104:producer produce 16104:product-5
[13899.284999] 16104:producer produce 16104:product-6
[13899.285002] 16104:producer produce 16104:product-7
[13899.285004] 16104:producer produce 16104:product-8
[13899.285007] 16104:producer produce 16104:product-9
[13899.339264] 16105:consumer start consume products...
[13899.339495] 16105:consumer consume 16104:product-0
[13899.339633] 16104:producer produce 16104:product-10
[13899.339769] 16105:consumer consume 16104:product-10
[13899.339907] 16104:producer produce 16104:product-11
[13899.340042] 16105:consumer consume 16104:product-11
[13899.340208] 16104:producer produce 16104:product-12
[13899.340344] 16105:consumer consume 16104:product-12
[13899.340481] 16104:producer produce 16104:product-13
[13899.340616] 16105:consumer consume 16104:product-13
[13899.340887] 16104:producer produce 16104:product-14
[13899.341036] 16105:consumer consume 16104:product-14
[13899.341175] 16104:producer produce 16104:product-15
[13899.341310] 16105:consumer consume 16104:product-15
[13899.341447] 16104:producer produce 16104:product-16
[13899.341582] 16105:consumer consume 16104:product-16
[13899.341719] 16104:producer produce 16104:product-17
[13899.341854] 16105:consumer consume 16104:product-17
[13899.342029] 16104:producer produce 16104:product-18
[13899.342164] 16105:consumer consume 16104:product-18
[13899.342302] 16104:producer produce 16104:product-19
[13899.342305] 16104:producer exit...
[13899.342525] 16105:consumer consume 16104:product-19
[13899.342663] 16105:consumer consume 16104:product-1
[13899.342808] 16105:consumer consume 16104:product-2
[13899.343060] 16105:consumer consume 16104:product-3
[13899.343214] 16105:consumer consume 16104:product-4
[13899.343352] 16105:consumer consume 16104:product-5
[13899.343489] 16105:consumer consume 16104:product-6
[13899.343625] 16105:consumer consume 16104:product-7
[13899.343762] 16105:consumer consume 16104:product-8
[13899.343899] 16105:consumer consume 16104:product-9
[13899.343902] 16105:consumer exit...
[14598.468929] Resolved the proceducer-consumer problem

Reply all
Reply to author
Forward
0 new messages