BUAA OS 作业:进程同步与PV操作

BUAA OS 作业:进程同步与PV操作


注:本文中的伪代码可能有的地方不符合题目要求,如发现有误或有更好的实现方式,麻烦大家指出或在评论区留言,谢谢!

第一题

读者写者问题(写者优先): 1)共享读; 2)互斥写、读写互斥; 3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。

int read_count = 0, write_count = 0;
semaphore read_mutex = 1, write_mutex = 1;
semaphore data_mutex = 1;  // 互斥访问共享数据
semaphore read = 1;

void writer() {
    while (true) {
        P(write_count);
        if (write_count++ == 0) P(read);  //只要有写者,就占着read
        V(write_count);
        
        P(data_mutex);
        // writing
        V(data_mutex);
        
        P(write_count);
        if (--write_count == 0) V(read);  //没有写者才释放read
        V(write_count);
    }
}

void reader() {
    while (true) {
        P(read);  // 没有写者才能进入临界区
        
        P(read_mutex);
        if (read_mutex++ == 0) P(data_mutex);
        V(read_mutex);
        
        V(read);
        
        // reading

        P(read_mutex);
        if (--read_mutex == 0) V(data_mutex);
        V(read_mutex);
    }
}

第二题

寿司店问题。假设一个寿司店有 5 个座位,如果你到达的时候有一个空座位,你可以立刻就坐。但是如果你到达的时候 5 个座位都是满的有人已经就坐,这就意味着这些人都是一起来吃饭的,那么你需要等待所有的人一起离开才能就坐。编写同步原语,实现这个场景的约束。

int wait_num = 0, eat_num = 0;
bool no_chairs = false;
semaphore mutex = 1; //互斥访问上面三个变量
semaphore block = 0;

void eat() {
    while (true) {
        P(mutex);
        if (no_chairs) { // 5个位置都满了,需要等所有人吃完
            wait_num++;  // mutex保证互斥
            P(block);
        } else {
            eat_num++;
            no_chairs = (eat_num == 5);
            V(mutex);
        }
        
        // eat
        
        P(mutex);
        eat_num--;
        if (eat_num == 0) {
            int n = min(wait_num, 5);
            wait_num -= n;
            eat_num += n;
            no_chairs = (n == 5);
            while (n--) V(block);
        }
        V(mutex);
    }
}

第三题

三个进程 P1、P2、P3 互斥使用一个包含 N(N>0)个单元的缓冲区。P1 每次用 produce()生成一个正整数并用 put()送入缓冲区某一个空单元中;P2 每次用getodd()从该缓冲区中取出一个奇数并用 countodd()统计奇数个数;P3 每次用 geteven()从该缓冲区中取出一个偶数并用 counteven()统计偶数个数。请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义的信号量的含义。要求用伪代码描述。

var mutex: semaphore := 1;  // 互斥信号量,互斥访问这N个单元
var even: semaphore := 0;  // 奇数数据的同步信号量,表示已占用缓冲区中偶数个数;
var odd: semaphore := 0;  // 偶数数据的同步信号量,表示已占用缓冲区中奇数个数;
var empty: semaphore := N;  // 缓冲区同步信号量,表示空闲缓冲区个数

// p1
begin
	repeat
		P(empty);
		var number: integer := produce();
		P(mutex);
		put(number);
		V(mutex);
		if (number % 2 = 0) then
			V(even);
		else
			V(odd);
	until false;
end

// p2
begin
	repeat
		P(odd);  // 不能先P(mutex)
		P(mutex);
		var ret: integer := getOdd();
		V(mutex);
		V(empty);
		countodd();
	until false;
end

//p3
begin
	repeat
		P(even);
		P(mutex);
		var ret: integer := getEven();
		V(mutex);
		V(empty);
		counteven();
	until false;
end.	

第四题

搜索-插入-删除问题。三个线程对一个单链表进行并发的访问,分别进行搜索、插入和删除。搜索线程仅仅读取链表,因此多个搜索线程可以并发。插入线程把数据项插入到链表最后的位置;多个插入线程必须互斥防止同时执行插入操作。但是,一个插入线程可以和多个搜索线程并发执行。最后,删除线程可以从链表中任何一个位置删除数据。一次只能有一个删除线程执行;删除线程之间,删除线程和搜索线程,删除线程和插入线程都不能同时执行。请编写三类线程的同步互斥代码,描述这种三路的分类互斥问题。

/* 优先级:搜索 > 插入 > 删除 */
int search_num = 0;
semaphore has_searchers = 1;
semaphore has_inserters = 1;
semaphore search_num_mutex = 1;  // 互斥访问search_num

void del() {
    while (true) {
        P(has_searchers);  //不能有其他搜索进程
        P(has_inserters);  //不能有其他插入进程
        // 上面两个信号量已经保证了del访问临界资源互斥,不需要另外新加信号量
		/* delete */
        V(has_inserters);
        V(has_searchers);
    }
}

void search() {
    while (true) {
        P(search_num_mutex);
        if (search_num++ == 0) {
            V(search_num_mutex);
            P(has_searchers);
        } else V(search_num_mutex);
        /* search */
        P(search_num_mutex);
        if (--search_num == 0) {
            V(has_searchers);
        }
        V(search_num_mutex);
    }
}

void insert() {
    while (true) {
        P(has_inserters);  // 保证insert之间互斥
        // 此时一定只有一个insert进程执行,不需对search进程数目限制,同时此时没有delete进程
        /* insert */
        V(has_inserters);
    }
}
posted @ 2022-05-03 20:01  NormalLLer  阅读(202)  评论(1编辑  收藏  举报