理发师多线程实现----面包师多进程实现
理发师问题的实现,多线程。
Linux 理发师、面包师程序文档
理发师问题
有一个理发师,一把理发椅和4把供等候理发的顾客坐的椅子。如果没有顾客,则理发师便在理发师椅子上睡觉;当一个顾客到来时,必须唤醒理发师进行理发;如果理发师正在理发时又有顾客来到,则如果有空椅子可坐,他就坐下来等,如果没有空椅子,他就离开。为理发师和顾客各编一段程序实现他们的行为。使用线程实现
初始化:顾客数为0,表示还没有顾客过来;理发师为0,表示理发师在睡觉;互斥信号量,用于控制临界区,防止同时修改waiting 值;椅子数为4,表示最多有4个顾客等待。
创建一个理发师线程,创建10个顾客进程,每次经过随机事件创建一个
程序流程图
代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <math.h>
#define CHAIRS 4
sem_t customers;//等待服务的顾客数
sem_t barbers;//等待顾客的理发师数
pthread_mutex_t mutex;//用于互斥
int waiting = 0;//等待的顾客
int if_no_more = 0;
void cut_hair()
{
printf("理发师:开始理发\n");
sleep(rand()%7 + 1);
}
void* barber()
{
while(1)
{
if(waiting == 0)
printf("理发师:当前没有顾客,睡觉\n");
sem_wait(&customers);//如果没有顾客,理发师睡,进程阻塞
pthread_mutex_lock(&mutex);//互斥进入临界区,欲修改waiting
waiting--;//等待理发人数减一
pthread_mutex_unlock( &mutex);//退出临界区,完成对waiting的修改
cut_hair();//理发师理发
sem_post(&barbers);//理发师结束理发barbers++
sleep(rand()%2 + 1);
if(if_no_more && waiting == 0)
break;
}
sleep(3);
printf("下班\n");
return;
}
void* customer()
{
int color = rand()%5+32;
#define START "\033[1;%dm"
#define END "\033[0m"
pthread_mutex_lock(&mutex);//互斥进入临界区,欲修改waiting
if(waiting<CHAIRS)//如果有空椅子
{
waiting++;//等待理发的人数加1
printf(START"新加了一位顾客%d\t等待理发人数:%d\n"END,color, (unsigned int)pthread_self(),waiting);
pthread_mutex_unlock( &mutex);//退出临界区,完成对waiting的修改
sem_post(&customers);//等待理发的人数加1,如有必要,唤醒理发师
sem_wait(&barbers);//理发师是否空闲,若忙则阻塞barbers--
printf(START"\t%d说:谢谢理发师。\n"END,color,(unsigned int)pthread_self());
}
else
{
printf(START"%d说:没有空椅子了,我换一家\n"END,31,(unsigned int)pthread_self());
pthread_mutex_unlock( &mutex);//没有空椅子,顾客离开
}
return;
}
int main()
{
int i;
pthread_t barber_id, customer_id;
sem_init(&customers, 0, 0);
sem_init(&barbers, 0, 0);
pthread_mutex_init( &mutex, NULL);
srand(time(0));
pthread_create( &barber_id, NULL, barber, NULL);
for(i=0; i<10;i++)
{
sleep(rand()%4 + 1);
pthread_create( &customer_id, NULL, customer, NULL);
}
if_no_more = 1;//后面没有客户了
pthread_join(barber_id,NULL);
return 0;
}
运行显示介绍
gcc ***.c -oxx -lpthread 编译
理发师:当没有顾客时,理发师睡觉
当有顾客时,理发师为一位顾客理发,等待理发的人数减1。
当不在有顾客来时,并且没有顾客在等待,理发师下班
顾客: 当有空椅子时:新加了一位顾客,等待理发的人数加1.
当没有空椅子时:没有空椅子了,我换一家。
运行结果
面包师问题:
面包师有很多面包和蛋糕,由 3 个销售人员销售。每个顾客进店后先取一个号,并且等着叫号。当一个销售人员空闲下来,就叫下一个号。请分别编写销售人员和顾客进程的程序。
使用多进程实现:
创建2个共用的信号量,waiting和free,waiting 初始值为3表示有3个售货员,free初始值为0表示初始没有顾客在等待。
:创建了三个销售人员进程来为顾客服务。
销售人员进程减少waiting的人数,在进程执行过程中,free人数会先减一,在为顾客服务完之后,free人数加一。
:一个顾客进程。
顾客进程增加waiting的人数
程序流程图:
代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/time.h>
#include <math.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define START "\033[1;%dm"
#define END "\033[0m"
#define MYKEY 2//制定信号灯集的标志
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
}sem1,sem2;
int semaphore_create();
int output_semaphore(int sid);
int up_num_of_waiting(int sid);
int down_num_of_waiting(int sid);
int up_num_of_free(int sid);
int down_num_of_free(int sid);
//创建信号集,并返回信号灯集描述字
int semaphore_create()
{
return semget(MYKEY, 2, IPC_CREAT);//key标识一个信号灯集,2表示创建2个信号量
}
//输出对应信号集中信号的数量
int output_semaphore(int sid)
{
printf("num of waiting: %d\n", semctl(sid, 0, GETVAL,sem1));//0信号量表示等待的人数
printf("num of free : %d\n", semctl(sid, 1, GETVAL,sem2));//1信号量表示空闲的服务员人数
}
int up_num_of_waiting(int sid)
{
/*
struct sembuf {
unsigned short sem_num; // 对应信号集中的信号灯
short sem_op; // 对信号灯的操作
short sem_flg; // 操作标志
};
*/
struct sembuf operation = {0, 1, SEM_UNDO};//等待人数加1
return semop(sid, &operation, 1);
}
int down_num_of_waiting(int sid)
{
struct sembuf operation = {0, -1, SEM_UNDO};//等待人数减一
return semop(sid, &operation, 1);
}
int up_num_of_free(int sid)
{
struct sembuf operation = {1, 1, SEM_UNDO};//空闲服务员人数加1
return semop(sid, &operation, 1);
}
int down_num_of_free(int sid)
{
struct sembuf operation = {1, -1, SEM_UNDO};//空闲服务员人数减1
return semop(sid, &operation, 1);
}
void customer()
{
int color = 34;
int sid = semaphore_create();
while(1)
{
up_num_of_waiting(sid);
printf("########顾客区########\n");
printf(START"一位顾客到了\n"END,color);
printf(START"num of waiting: %d\n"END, color,semctl(sid, 0, GETVAL,sem1));
printf(START"num of free: %d\n"END, color,semctl(sid, 1, GETVAL,sem2));
//output_semaphore(sid);
printf("######################\n");
//sleep(0.5);
//output_semaphore(sid);
//sleep(0.5);
//down_num_of_free(sid);
//output_semaphore(sid);
//printf(START"一个销售人员空闲,并为顾客服务 \n"END,color);
sleep(rand()%2 + 1);
//up_num_of_free(sid);
}
}
void salesman()
{
int color = 33;
int pid = getpid();
int sid = semaphore_create();
while(1)
{
down_num_of_waiting(sid);
//sleep(1);
down_num_of_free(sid);
printf("********销售区********\n");
printf(START"销售员%d: 为顾客提供服务,空闲人数减一,等待人数减一\n"END,color,pid);
//printf(START"num of waiting: %d\n"END, color,semctl(sid, 0, GETVAL,sem1));
//printf(START"num of free: %d\n"END, color,semctl(sid, 1, GETVAL,sem2));
//output_semaphore(sid);
printf("*********************\n");
sleep(rand()%10 + 1);
up_num_of_free(sid);
}
}
//将所有信号量置初始值
void init()
{
int sid = semaphore_create();
sem1.val = 0;
sem2.val = 3;
semctl(sid, 0, SETVAL, sem1);
semctl(sid, 1, SETVAL, sem2);
}
int main()
{
init();
pid_t sale1,sale2,sale3;
srand(time(0));
sale1 = fork();
if(sale1 == 0 )
{
salesman();
}
sale2 = fork();
if(sale2 == 0 )
{
salesman();
}
sale3 = fork();
if(sale3 == 0 )
{
salesman();
}
else
{
customer();
}
return 0;
}
运行显示介绍:
顾客进程输出:
########顾客区########
一位顾客到了
num of waiting: x
num of free: x
######################
售货员进程输出:
********销售区********
销售员xx:为顾客提供服务,空闲人数减一,等待人数减一
**********************
因为进程可以同时输出,所以会交叉输出,因此设置了界限,这样在看程序输出时,通过界限及不同进程的输出语句,可以较清晰地看到结果
运行结果: