XXXXXXXXXXXXXXX 课程设计题目用多线程同步方法解决睡眠理发师问题(Sleeping-Barber Problem) 学院计算机科学与技术学院专业软件工程班级姓名指导教师2010 年 6 月28 日课程设计任务书学生姓名:专业班级:指导教师:工作单位:题目: 用多线程同步方法解决睡眠理发师问题(Sleeping-Barber Problem)初始条件:1.操作系统:Linux2.程序设计语言:C语言3. 设有一个理发师,5把椅子(另外还有一把理发椅),几把椅子可用连续存储单元。
要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)1.技术要求:1)为每个理发师/顾客产生一个线程,设计正确的同步算法2)每个顾客进入理发室后,即时显示“Entered”及其线程自定义标识,还同时显示理发室共有几名顾客及其所坐的位置。
3)至少有10个顾客,每人理发至少3秒钟。
4)多个顾客须共享操作函数代码。
2.设计说明书内容要求:1)设计题目与要求2)总的设计思想及系统平台、语言、工具等。
3)数据结构与模块说明(功能与流程图)4)给出用户名、源程序名、目标程序名和源程序及其运行结果。
(要注明存储各个程序及其运行结果的主机IP地址和目录。
)5)运行结果与运行情况(提示: (1)连续存储区可用数组实现。
(2)编译命令可用:cc -lpthread -o 目标文件名源文件名(3)多线程编程方法参见附件。
)3. 调试报告:1) 调试记录2)自我评析和总结上机时间安排:18周一~ 五08:0 -12:00指导教师签名:年月日系主任(或责任教师)签名:年月日目录1设计题目与要求 (4)1.1 设计题目 (4)1.2 设计要求 (4)1.2.1 初始条件 (4)1.2.2 技术要求 (4)2 总体设计思想及开发环境与工具 (4)2.1 总体设计思想 (4)2.2 多线程编程原理 (5)2.2.1 创建一个线程 (5)2.2.2 等待一个线程结束 (5)2.2.3 信号量 (6)2.3 伪码实现 (6)2.4 开发环境与工具 (7)3数据结构与模块说明 (8)3.1 数据结构 (8)3.2程序模块说明 (8)3.2.1主函数模块 (8)3.2.2 理发师模块 (9)3.2.3 顾客模块 (9)4源程序 (10)4.1用户名、源程序名和目标程序名 (10)4.2源程序代码 (11)5运行结果 (14)5.1运行步骤 (14)5.2运行结果 (15)5.2.1 编辑,编译和运行的过程图 (15)5.2.2 错误部分截图 (16)5.2.3 正确运行结果图 (16)6调试记录 (18)6.1调试记录 (18)6.2自我评析和总结 (19)7参考文献 (19)1设计题目与要求1.1 设计题目用多线程同步方法解决睡眠理发师问题(Sleeping-Barber Problem)1.2 设计要求1.2.1 初始条件(1)操作系统:Linux(2)程序设计语言:C语言(3)设有一个理发师,5把椅子(另外还有一把理发椅),几把椅子可用连续存储单元。
1.2.2 技术要求(1)为每个理发师/顾客产生一个线程,设计正确的同步算法(2)每个顾客进入理发室后,即时显示“Entered”及其线程自定义标识,还同时显示理发室共有几名顾客及其所坐的位置。
(3)至少有10个顾客,每人理发至少3秒钟。
(4)多个顾客须共享操作函数代码。
2 总体设计思想及开发环境与工具2.1 总体设计思想题目中要求描述理发师和顾客的行为,因此需要两类线程barber()和customer ()分别描述理发师和顾客的行为。
其中,理发师有活动有理发和睡觉两个事件;等待和理发二个事件。
店里有固定的椅子数,上面坐着等待的顾客,顾客在到来这个事件时,需判断有没有空闲的椅子,理发师决定要理发或睡觉时,也要判断椅子上有没有顾客。
所以,顾客和理发师之间的关系表现为:(1)理发师和顾客之间同步关系:当理发师睡觉时顾客近来需要唤醒理发师为其理发,当有顾客时理发师为其理发,没有的时候理发师睡觉。
(2)理发师和顾客之间互斥关系:由于每次理发师只能为一个人理发,且可供等侯的椅子有限只有n把,即理发师和椅子是临界资源,所以顾客之间是互斥的关系。
(3)故引入3个信号量和一个控制变量:ⅰ控制变量waiting用来记录等候理发的顾客数,初值为0;ⅱ信号量customers用来记录等候理发的顾客数,并用作阻塞理发师进程,初值为0;ⅲ信号量barbers用来记录正在等候顾客的理发师数,并用作阻塞顾客进程,初值为1;ⅳ信号量mutex用于互斥,初值为12.2 多线程编程原理此次在Linux下进行多线程编程需要用到pthread_create和pthread_join这两个函数。
2.2.1 创建一个线程pthread_create用来创建一个线程,原型为:extern int pthread_create((pthread_t *__thread, __const pthread_attr_t *__attr,void *(*__start_routine) (void *), void *__arg))第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。
函数thread不需要参数时,最后一个参数设为空指针。
第二个参数设为空指针时,将生成默认属性的线程。
创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
2.2.2 等待一个线程结束pthread_join用来等待一个线程的结束,函数原型为:extern int pthread_join __P ((pthread_t __th, void **__thread_return));第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。
这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。
2.2.3 信号量(1)函数sem_init()用来初始化一个信号量,函数原型为:extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。
(2)函数sem_post( sem_t *sem )用来增加信号量的值。
当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。
(3)函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。
函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。
2.3 伪码实现difine n 5; //为顾客准备的椅子数为5semaphore mutex=1; //用于互斥semaphore customers=0;//等候理发的顾客数semaphore barbers=1;//正在等候顾客的理发师数int waiting=0; //等候理发的顾客数//理发师线程void barber(){while(true) //判断有无顾客{wait(customers); //若无顾客,理发师睡眠wait(mutex); //互斥waiting--; //等候顾客数少一个signal(mutex); //释放临界资源signal(barber); //理发师去为一个顾客理发cut_hair; //正在理发}}//顾客线程void customer(){wait(mutex); //互斥if (waiting<n) //如果有空椅子,则等待{waiting++; //等候顾客数加1signal(mutex); //释放临界资源signal(customers); //如果理发师睡觉,唤醒理发师 wait(barber); //理发师在理发, 顾客等候get_haircut; //顾客坐下等理发师}elsesignal(mutex); //店里人满了,顾客离开}}2.4 开发环境与工具系统平台:LINUX环境实现语言:C语言开发工具:NANO编辑器3数据结构与模块说明3.1 数据结构通过分析课程设计要求,定义以下的数据:sem_t mutex,customers,barbers;//design three semaphores: mutex,customer,barbers int waiting=0; //the number of waiting customersint chair[5];3.2程序模块说明3.2.1主函数模块主函数流程图如下:3.2.2 理发师模块理发师模块函数流程图如下:3.2.3 顾客模块顾客模块函数流程图如下:4源程序4.1用户名、源程序名和目标程序名用户名:rj070234源程序名:SleepingBarber.c目标程序名:SleepingBarber主机IP地址:192.168.1.2544.2源程序代码#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include<semaphore.h>#include<fcntl.h>#include<errno.h>#define n 5 //the shop have five chairs//design three semaphores: mutex,customer,barberssem_t mutex,customers,barbers;int waiting=0; //the number of waiting customersint chair[5];void * barber();void * customer(void *arg);int main(int argc,char *argv[]){//create 10 semaphores and one Barber semaphorepthread_t Customer_id[10],Barber_id;int i;sem_init(&mutex,0,1); //init mutex semaphore to 1sem_init(&customers,0,0);//init semaphore customers to 0 sem_init(&barbers,0,1);for(i=0;i<5;i++)pthread_create(&Barber_id,NULL,(void*)barber,NULL);for (i=0;i<10;i++)pthread_create(&Customer_id[i],NULL,(void*)customer,(void*)(i+1)); for (i=0;i<10;i++)pthread_join(Customer_id[i],NULL);for(i=0;i<5;i++)pthread_join(Barber_id,NULL);return 0;}//creat barber pthreadvoid * barber(){int i;int next;//wait(customers),if no customers,barber sleepingsem_wait(&customers);sem_wait(&mutex); //wait(mutex)waiting--; //the numer of waiting reduce onefor(i=0;i<5;i++){if (chair[i]!=0){next= chair[i];chair[i]=0;break;}}printf("The barber is cutting %dth customer's hair\n",next);sleep(3);sem_post(&mutex);sem_post(&barbers);}//creat customer pthreadvoid * customer(void *arg){int i;sem_wait(&mutex); //wait(mutex) if(waiting<n)if(waiting<n){waiting++; //the numer of waiting plus onefor(i=0;i<5;i++){if (chair[i]==0){chair[i]=(int)arg;break;}}printf("***************************************************\n");printf("Entered:Number %d customer comes,and sits at %d chair \n",(int)arg,(i+1));printf("There are %d customer on the chair\n",waiting);printf("The customers' location are:");for(i=0;i<5;i++)printf("%d ",chair[i]);printf("\n");sleep(1);sem_post(&mutex); //signal(mutex)sem_post(&customers); //signal(customers)sem_wait(&barbers); //wait(barbers)}else{printf("Number %d comes,there are no chairs,the customer %d is leaving\n",(int)arg,(int)arg);sem_post(&mutex);}}5运行结果5.1运行步骤(1) 打开桌面上的putty.exe,输入IP地址192.168.1.254,进入开发环境。