【MIT6.828】【LAB Utilities 3】primes

【MIT6.828】【LAB Utilities 3】primes


前言

使用管道编写prime的并发版本。这个想法源于Unix管道的发明者道格·麦克洛伊。下面说明了如何实现。您的解决方案应该在文件user/primes.c中。
您的目标是使用pipe和fork来设置管道。第一个过程将数字2到35送入管道。对于每个素数,您将创建一个进程,该进程通过一个管道从其左侧邻居读取数据,并通过另一个管道向其右侧邻居写入数据。由于xv6具有有限数量的文件描述符和进程,因此第一个进程可以在35停止。


提示

  1. 请小心关闭进程不需要的文件描述符,否则程序将在第一个进程到达35之前耗尽资源。
  2. 一旦第一个进程达到35,您应该安排管道干净地终止,包括所有子进程(提示:当管道的写端关闭时,read将返回文件结尾)。
  3. 直接将32位int写入管道是最简单的,而不是使用格式化的ASCII I/O。
  4. 应该根据需要在管道中创建流程。

实现

代码如下(示例):

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

void primes(int p[])
{
    int res;
    if (!read(p[0], &res, 4)) {
        // fprintf(2, "End not in main pid:%d.\n", getpid());
        exit(0);
    }
    fprintf(2, "prime %d\n", res);
    int c[2];
    pipe(c);
    if (fork() == 0) {
        close(p[0]);
        close(c[1]);
        primes(c);
    } else {
        close(c[0]);
        int tmp;
        while(read(p[0], &tmp, 4)) {
            if (tmp % res != 0) {
                write(c[1], &tmp, 4);
            }
        }
        close(p[0]);
        close(c[1]);
        wait((int *) 0);
    }
}
int
main(int argc, char *argv[])
{
    int p0[2];
    pipe(p0);
    for (int i = 2; i <= 35; i++) {
        write(p0[1], &i, 4);
    }
    close(p0[1]);
    primes(p0);
    // fprintf(2, "End in main pid:%d.\n", getpid());
    exit(0);
}

结果

init: starting sh
$ primes
prime 2
prime 3
prime 5
prime 7
prime 11
prime 13
prime 17
prime 19
prime 23
prime 29

总结

本题非常精妙,作为初学者进一步加深了对fork,pipe,read,write的理解。
程序流程示意,其重点并不在筛去合数的过程,而在于进程间通信的方式

线程1从父管线p0读队头print2起动线程2创建管线c1(此时为空)筛掉2的倍数剩余塞入管线c1
线程2从父管线c1读(等待父进程塞入数据)print 3起动线程3创建管线c2(此时为空)筛掉3的倍数剩余塞入管线c2
线程3从父管线c2读(等待父进程塞入数据)print 5起动线程4创建管线c3(此时为空)筛掉5的倍数剩余塞入管线c3
… …… …

个人对于题目的疑惑和理解

  1. 关于代码中使用的wait((int *) 0);,看到别人写的代码里有等待子线程结束的地方,一开始不太理解,后来把这行删掉了之后发现输出如下
$ primes
prime 2
prime 3
prime 5
prime 7
prime $ 11
prime 13
prime 17
prime 19
prime 23
prime 29
prime 31

可以看到结果是大致正确的,主进程提前结束导致程序提前回到了命令行$

  1. read函数在没有读到想要的值时是会一直等待的,如提示中所写,当管道的写端关闭时,read将返回文件结尾,返回值为0,当管道的读端关闭read返回-1。
  2. 很重要的一点,fork出的不同线程中的fd状态是不会共享的,在另一个线程中close一个pipe对本进程无影响,但他们的值和地址一致,推测只是引用计数。
  3. 所有fork出的线程都还是会从main退出,如本题代码中的两行注释取消掉得到的输出如下。
init: starting sh
$ primes
prime 2
prime 3
prime 5
prime 7
prime 11
prime 13
prime 17
prime 19
prime 23
prime 29
prime 31
End not in main pid:14.
End in main pid:13.
End in main pid:12.
End in main pid:11.
End in main pid:10.
End in main pid:9.
End in main pid:8.
End in main pid:7.
End in main pid:6.
End in main pid:5.
End in main pid:4.
End in main pid:3.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值