【Nachos】山东大学操作系统实验三 使用信号量解决生产者消费者同步问题

完整源码见本人博客下载资源

一、完成情况概览

  • 熟悉了解了nachos同步机制,信号量,锁,条件变量与管程。
  • 用信号量解决生产者/消费者同步问题
  • 用管程解决生产者/消费者同步问题

二、Nachos的同步机制研究

以下三个类均定义在threads/sync.h 文件中

1、class Semaphore

信号量属于一种低级进程或线程通信原语,p()和v()操作的原子性通过开关中断来实现;

queue队列,存放wait线程,避免忙等;

class Semaphore {
  public:
    Semaphore(char* debugName, int initialValue);	// set initial value
    ~Semaphore();   					// de-allocate semaphore
    char* getName() { return name;}			// debugging assist
    
    void P();	 // these are the only operations on a semaphore
    void V();	 // they are both *atomic*
    
  private:
    char* name;        // useful for debugging
    int value;         // semaphore value, always >= 0
    List *queue;       // threads waiting in P() for the value to be > 0
};
2、class Lock

lock是用值是一的semaphore实现的;lock是之后的条件变量的成员,isHeldByCurrentThread()为管程的实现带来便利。

class Lock {
  public:
    Lock(char* debugName);  		// initialize lock to be FREE
    ~Lock();				// deallocate lock
    char* getName() { return name; }	// debugging assist

    void Acquire(); // these are the only operations on a lock
    void Release(); // they are both *atomic*
    bool isHeldByCurrentThread();
  private:
    char* name;				// for debugging
    Thread *owner;                      // remember who acquired the lock
    Semaphore *lock;                    // use semaphore for the actual lock
};
3、class Condition

condition是管程的重要成员;它与semaphore的差别是,p和v操作,需要传一个参数lock进去。

class Condition {
  public:
    Condition(char* debugName);		// initialize condition to 
					// "no one waiting"
    ~Condition();			// deallocate the condition
    char* getName() { return (name); }    
    void Wait(Lock *conditionLock); 	// these are the 3 operations on 
					// condition variables; releasing the 
					// lock and going to sleep are 
					// *atomic* in Wait()
    void Signal(Lock *conditionLock);   // conditionLock must be held by
    void Broadcast(Lock *conditionLock);// the currentThread for all of 
					// these operations
  private:
    char* name;
    List* queue;  // threads waiting on the condition
    Lock* lock;   // debugging aid:  used to check correctness of
                  // arguments to Wait, Signal and Broacast
};

三、使用信号量解决生产者/消费者同步问题

1、实现思路与步骤

如上所述,信号量nachos已经实现;生产者消费者问题的代码框架已经给出,只需要在合适的位置,填入空缺的代码。

要填的有以下几部分:

1)初始化信号量

考虑需要什么样的信号量:

生产者之前的锁——不能同时写;消费者之间的锁——不能同时读;

buffer有货物可消费的信号量——sem_consume;buffer有空可写的信号量——sem_produce;

注意:对于buffer,有货物时,可以同时读写,所以定一个锁,使得一个时刻只能一个人访问buffer,是低效的。

mutex_produce=new Lock("mutex_produce");
    mutex_consume=new Lock("mutex_consume");
    sem_produce=new Semaphore("sem_produce",BUFF_SIZE);//empty
    sem_consume=new Semaphore("sem_consume",0);//full
2)生产者,消费者线程创建
Thread *t = new Thread(prod_names[i]);
      t->Fork(Producer, i);
3)生产者函数控制
message=new slot(which,num);
sem_produce->P();
mutex_produce->Acquire();
ring->Put(message);
mutex_produce->Release();
sem_consume->V();
4)消费者函数控制
sem_consume->P();
mutex_consume->Acquire();   
ring->Get(message);
 mutex_consume->Release();
sem_produce->V();
2、结果展示

在这里插入图片描述
在这里插入图片描述

四、使用管程解决生产者/消费者同步问题

1、实现思路与步骤

用管程解决该问题,不能套用一给出的代码框架。

需要自己利用condition和lock,根据管程思想,写一个Ring类,这样,访问ring的人只需要简单的调用put,get函数,不需要考虑同步细节。

1)管程类Ring2
class Ring2 { 
  public: 
  Ring2(int sz); // Constructor: initialize variables, allocate space. 
  ~Ring2(); // Destructor: deallocate space allocated above. 

  void Put(slot *message); // Put a message the next empty slot. 
  void Get(slot *message); // Get a message from the next full slot. 
  int Full(); // Returns non0 if the ring is full, 0 otherwise. 
  int Empty(); // Returns non0 if the ring is empty, 0 otherwise. 

 private: 
  int size; // The size of the ring buffer. 
  int in, out; // Index of Put and Get 
  slot *buffer; // A pointer to an array for the ring buffer. 
  int current; // the current number of full slots in the buffer 
  Condition *notfull; // condition variable to wait until not full 
  Condition *notempty; // condition variable to wait until not empty 
  Lock *mutex; //semaphore for the mutual exclusion 
  //Semaphore *next; //semaphore for "next" queue 
  //int next_count; // the number of threads in "next" queue 
};

具体实现:

2)使用管程Ring2的生产者,消费者程序
ring2=new Ring2(BUFF_SIZE); 
void Producer2(_int which) 
{ 
	int num; 
	slot *message; 

	for (num = 0; num < N_MESSG ; num++) { 
	// the code to prepare the message goes here. 
	message=new slot(which,num);
	ring2->Put(message); 
} 
} 
//对于消费者的过程:
void Consumer2(_int which) 
{ 
	char str[MAXLEN]; 
	char fname[LINELEN]; 
	int fd; 
	slot *message = new slot(0,0); 

	sprintf(fname, "tmp_%d", which); 
	printf("file name is %s \n", fname); 
	if ( (fd = creat(fname, 0600) ) == 1) 
	{ 
		perror("creat: file create failed"); 
		return;
	} 
	for (; ; ) { 
		ring2->Get(message); 
		sprintf(str,"producer id > %d; Message number > %d;\n", 
		message->thread_id, 
		message->value); 
		if ( write(fd, str, strlen(str)) == 1 ) { 
			perror("write: write failed"); 
			return;
		} 
	} 
}
2、结果展示

在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值