操作系统NACHOS实验(三)使用信号量解决生产者/消费者同步问题
实验思路
Lab3文件夹中已经给出了本次实验需要使用的一些类定义,比如环形缓冲区Ring类等,我们所要完成的就是在prodcons++.cc中补充相关代码。
首先需要完善信号量的初始化
mutex=new Semaphore("mutex",1); nempty=new Semaphore("nempty",BUFF_SIZE); nfull=new Semaphore("nfull",0);
接下来就是定义临界区,对于临界区的定义要注意各个信号量操作的顺序。
关键源代码注释以及程序说明
prodcons++.cc代码
…… //添加的头文件 #include <fcntl.h> #include <stdlib.h> #include <unistd.h> …… void Producer(_int which) { int num; slot *message = new slot(0,0); // This loop is to generate N_MESSG messages to put into to ring buffer // by calling ring->Put(message). Each message carries a message id // which is represened by integer "num". This message id should be put // into "value" field of the slot. It should also carry the id // of the producer thread to be stored in "thread_id" field so that // consumer threads can know which producer generates the message later // on. You need to put synchronization code // before and after the call ring->Put(message). See the algorithms in // page 182 of the textbook. for (num = 0; num < N_MESSG ; num++) { // Put the code to prepare the message here. // ... message->value=num; message->thread_id=which; // Put the code for synchronization before ring->Put(message) here. // ... nempty->P();//空槽信号量减 mutex->P();//互斥信号量 ring->Put(message); // Put the code for synchronization after ring->Put(message) here. // ... mutex->V();//释放互斥信号量 nfull->V();//满槽信号量加 } } //---------------------------------------------------------------------- // Consumer // endless loop to fetch messages from the ring buffer and // record these message in the corresponding file. // //---------------------------------------------------------------------- void Consumer(_int which) { char str[MAXLEN]; char fname[LINELEN]; int fd; slot *message = new slot(0,0); // to form a output file name for this consumer thread. // all the messages received by this consumer will be recorded in // this file. sprintf(fname, "tmp_%d", which); // create a file. Note that this is a UNIX system call. if ( (fd = creat(fname, 0600) ) == -1) { perror("creat: file create failed"); exit(1); } for (; ; ) { // Put the code for synchronization before ring->Get(message) here. // ... nfull->P();//满槽信号量减 mutex->P();//互斥信号量阻塞 ring->Get(message); // Put the code for synchronization after ring->Get(message) here. // ... mutex->V();//释放 nempty->V();//空槽信号量加 // form a string to record the message sprintf(str,"producer id --> %d; Message number --> %d;\n", message->thread_id, message->value); // write this string into the output file of this consumer. // note that this is another UNIX system call. if ( write(fd, str, strlen(str)) == -1 ) { perror("write: write failed"); exit(1); } } } //---------------------------------------------------------------------- // ProdCons // Set up semaphores for shared round buffer and // create and fork producers and consumer threads //---------------------------------------------------------------------- void ProdCons() { int i; DEBUG('t', "Entering ProdCons"); // Put the code to construct all the semaphores here. // .... mutex=new Semaphore("mutex",1); nempty=new Semaphore("nempty",BUFF_SIZE); nfull=new Semaphore("nfull",0); // Put the code to construct a ring buffer object with size //BUFF_SIZE here. // ... ring=new Ring(BUFF_SIZE); // create and fork N_PROD of producer threads for (i=0; i < N_PROD; i++) { // this statemet is to form a string to be used as the name for // produder i. sprintf(prod_names[i], "producer_%d", i); // Put the code to create and fork a new producer thread using // the name in prod_names[i] and // integer i as the argument of function "Producer" // ... producers[i]=new Thread(prod_names[i]); producers[i]->Fork(Producer, i); }; // create and fork N_CONS of consumer threads for (i=0; i < N_CONS; i++) { // this statemet is to form a string to be used as the name for // consumer i. sprintf(cons_names[i], "consumer_%d", i); // Put the code to create and fork a new consumer thread using // the name in cons_names[i] and // integer i as the argument of function "Consumer" // ... consumers[i]=new Thread(cons_names[i]); consumers[i]->Fork(Consumer,i); }; }
调试记录
第一次make报错,原因是引用成员变量使用了点而不是箭头。
修改代码后,执行依旧报错,但错误是creat函数未定义。在代码中,creat函数是UNIX的系统调用。随后添加了#include <fcntl.h>#include <stdlib.h>#include <unistd.h> 三个头文件,问题解决。
一开始总是只有temp_1中有数据,在查看main.cc后发现命令
-rs causes Yield to occur at random (but repeatable) spots
,给予其一定值,输出如下: