Pintos斯坦福操作系统Project0思路详解及源码


题目信息

思路详解

caltrain

这道题的主要思路是,车站里乘客分为两种,一种是候车乘客,一种是检票等车旅客。每当到来一个乘客,就增加一个乘客线程,乘客必须等待火车到来并且还有座位才能去排队检票等车;火车必须等待所有乘客都检票完成上车才能离开。

ok,那么按照思路,我们可以看到两个等待的过程,一个是乘客等车,一个是火车等乘客,所以可以设置两个信号量,作为唤醒等待的标志。

struct station {
	
    struct lock mutex;      //control critical section
    struct condition arrival;    //signal when train arrives station
    struct condition leaving;    //signal when train is ready to leave

    int seats;                      //available seats
    int waiting_passengers;         //passengers on station
    int leaving_passengers;         //passengers on board
};

之后初始化,由于最开始没有车到站也没有乘客来,所以这些变量都是0。

void
station_init(struct station *station)
{
    station->seats=0;
    station->waiting_passengers = 0;//in station
    station->leaving_passengers = 0;//on board
    lock_init(&(station->mutex));
    cond_init(&(station->arrival));
    cond_init(&(station->leaving));
}

按照题目要求给出的三个函数,现在逐一解决。

第一个函数表示列车到站,或者说用来控制列车的行为,当车辆到站时会唤醒(cond_broadcast)所有的乘客线程,之后等待(cond_wait)可以离开的信号。

需要注意的是当车站没人或者这个车开过来的时候就一个座位都没有,就不必等待可以直接返回了。这个时候,因为会有乘客同时一下子都来的情况,所以必须要加锁。

void
station_load_train(struct station *station, int count)
{
	lock_acquire(&(station->mutex));
    if(count == 0 || station->waiting_passengers == 0){  //passenger may come at the same moment train arrives
        lock_release(&(station->mutex));        //Race_Condition, must use mutex here
        return;
    }
    station->seats = count;
    cond_broadcast(&(station->arrival),&(station->mutex));//wake up all waitiing passengers
    cond_wait(&(station->leaving), &(station->mutex));//waiting to leave
    lock_release(&(station->mutex));
}

第二个函数表示乘客候车,车站来一个乘客候车人数就加一,当没有座位时,乘客就要等待新的列车到来。如果还有座位,乘客就去排队检票,检票人数增加,候车人数减少。

void
station_wait_for_train(struct station *station)
{
	lock_acquire(&(station->mutex));
    station->waiting_passengers++;
    while(station->seats == 0){
        cond_wait(&(station->arrival),&(station->mutex));
    }
    station->seats--;
    station->waiting_passengers--;
    station->leaving_passengers++;
    lock_release(&(station->mutex));
}

第三个函数表示乘客登车,只有检票的人全部上车,并且车站没有候车的人或者列车没有剩余座位了,才能告诉列车它可以离开了。

void
station_on_board(struct station *station)
{
	lock_acquire(&(station->mutex));
    station->leaving_passengers--;
	if(station->leaving_passengers == 0 && (station->seats == 0 || station->waiting_passengers == 0))
        cond_signal(&(station->leaving),&(station->mutex));
    lock_release(&(station->mutex));
}

测试也没什么问题啦!

在这里插入图片描述

reaction

踩坑记录:混淆signal用法,signal一次只能唤醒随机一个线程,我的1.0版本只用到了一个信号量,无法区别H和O唤醒哪个线程,就没有办法在产生一次反应时释放两个H一个O,以下是我的1.0错误示范:

#include "pintos_thread.h"

// Forward declaration. This function is implemented in reaction-runner.c,
// but you needn't care what it does. Just be sure it's called when
// appropriate within reaction_o()/reaction_h().
void make_water();

struct reaction {
	struct lock mutex;      //control critical section
    struct condition StartReaction; 

	int waiting_H;
	int waiting_O;
};

void
reaction_init(struct reaction *reaction)
{
    reaction->waiting_H = 0;
    reaction->waiting_O = 0;
    lock_init(&(reaction->mutex));
    cond_init(&(reaction->StartReaction));
}

void
reaction_h(struct reaction *reaction)
{
	lock_acquire(&(reaction->mutex));
	reaction->waiting_H++;
	while(reaction->waiting_H <2 || reaction->waiting_O<1){
		cond_wait(&(reaction->StartReaction),&(reaction->mutex));
	}
	make_water();
	cond_signal(&(reaction->StartReaction),&(reaction->mutex));
	cond_signal(&(reaction->StartReaction),&(reaction->mutex));
	reaction->waiting_H -= 2;
	reaction->waiting_O --;
	lock_release(&(reaction->mutex));
}

void
reaction_o(struct reaction *reaction)
{
	lock_acquire(&(reaction->mutex));
	reaction->waiting_O++;
	while(reaction->waiting_H <2 || reaction->waiting_O<1){
		cond_wait(&(reaction->StartReaction),&(reaction->mutex));
	}
	make_water();
	cond_signal(&(reaction->StartReaction),&(reaction->mutex));
	reaction->waiting_H -= 2;
	reaction->waiting_O -=1;
	lock_release(&(reaction->mutex));
}

回到正题,按照题目要求,需要每次反应都返回两个H一个O,两种不同的原子就需要分别用两个信号量返回。

struct reaction {
	struct lock mutex;      //control critical section
    struct condition H_reaction;   
	struct condition O_reaction;   
	
	int waiting_H;	//waiting H number
	int waiting_O;	//waiting O number
};

每当来了一个H,它就会告诉O我们这边来了一个H,之后就等待O在告诉它反应完成。

void
reaction_h(struct reaction *reaction)
{
	lock_acquire(&(reaction->mutex));
	reaction->waiting_H++;
	cond_signal(&(reaction->O_reaction),&(reaction->mutex));	//a H come
	cond_wait(&(reaction->H_reaction),&(reaction->mutex));	//waiting for reaction
	lock_release(&(reaction->mutex));
}

我将反应条件判断放在了O这边,当满足条件时就反应,同时唤醒两个H信号量让他们返回,不满足条件就一直while等待足够的H。

void
reaction_o(struct reaction *reaction)
{
	lock_acquire(&(reaction->mutex));
	reaction->waiting_O++;
	while(reaction->waiting_H <2 || reaction->waiting_O<1){
		cond_wait(&(reaction->O_reaction),&(reaction->mutex));	//waiting for H and repeat the while until reaction
	}
	make_water();
	reaction->waiting_H -= 2;
	reaction->waiting_O -=1;
	cond_signal(&(reaction->H_reaction),&(reaction->mutex));
	cond_signal(&(reaction->H_reaction),&(reaction->mutex));
	lock_release(&(reaction->mutex));
}

测试成功,project 0完成!
在这里插入图片描述

源代码

caltrain.c

#include "pintos_thread.h"

struct station {
	
    struct lock mutex;      //control critical section
    struct condition arrival;    //signal when train arrives station
    struct condition leaving;    //signal when train is ready to leave

    int seats;                      //available seats
    int waiting_passengers;         //passengers on station
    int leaving_passengers;         //passengers on board
};

void
station_init(struct station *station)
{
    station->seats=0;
    station->waiting_passengers = 0;//in station
    station->leaving_passengers = 0;//on board
    lock_init(&(station->mutex));
    cond_init(&(station->arrival));
    cond_init(&(station->leaving));
}

void
station_load_train(struct station *station, int count)
{
	lock_acquire(&(station->mutex));
    if(count == 0 || station->waiting_passengers == 0){  //passenger may come at the same moment train arrives
        lock_release(&(station->mutex));        //Race_Condition, must use mutex here
        return;
    }
    station->seats = count;
    cond_broadcast(&(station->arrival),&(station->mutex));
    cond_wait(&(station->leaving), &(station->mutex));
    lock_release(&(station->mutex));
}

void
station_wait_for_train(struct station *station)
{
	lock_acquire(&(station->mutex));
    station->waiting_passengers++;
    while(station->seats == 0){
        cond_wait(&(station->arrival),&(station->mutex));
    }
    station->seats--;
    station->waiting_passengers--;
    station->leaving_passengers++;
    lock_release(&(station->mutex));
}

void
station_on_board(struct station *station)
{
	lock_acquire(&(station->mutex));
    station->leaving_passengers--;
	if(station->leaving_passengers == 0 && (station->seats == 0 || station->waiting_passengers == 0))
        cond_signal(&(station->leaving),&(station->mutex));
    lock_release(&(station->mutex));
}

reaction.c

#include "pintos_thread.h"

// Forward declaration. This function is implemented in reaction-runner.c,
// but you needn't care what it does. Just be sure it's called when
// appropriate within reaction_o()/reaction_h().
void make_water();

struct reaction {
	struct lock mutex;      //control critical section
    struct condition H_reaction;   
	struct condition O_reaction;   

	int waiting_H;	//waiting H number
	int waiting_O;	//waiting O number
};

void
reaction_init(struct reaction *reaction)
{
    reaction->waiting_H = 0;
    reaction->waiting_O = 0;
    lock_init(&(reaction->mutex));
    cond_init(&(reaction->H_reaction));
    cond_init(&(reaction->O_reaction));
}

void
reaction_h(struct reaction *reaction)
{
	lock_acquire(&(reaction->mutex));
	reaction->waiting_H++;
	cond_signal(&(reaction->O_reaction),&(reaction->mutex));	//a H come
	cond_wait(&(reaction->H_reaction),&(reaction->mutex));	//waiting for reaction
	lock_release(&(reaction->mutex));
}

void
reaction_o(struct reaction *reaction)
{
	lock_acquire(&(reaction->mutex));
	reaction->waiting_O++;
	while(reaction->waiting_H <2 || reaction->waiting_O<1){
		cond_wait(&(reaction->O_reaction),&(reaction->mutex));	//waiting for H and repeat the while until reaction
	}
	make_water();
	reaction->waiting_H -= 2;
	reaction->waiting_O -=1;
	cond_signal(&(reaction->H_reaction),&(reaction->mutex));
	cond_signal(&(reaction->H_reaction),&(reaction->mutex));
	lock_release(&(reaction->mutex));
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值