难度: hard/moderate

Write a concurrent prime sieve program for xv6 using pipes and the design illustrated in the picture halfway down  this page and the surrounding text. This idea is due to Doug McIlroy, inventor of Unix pipes. Your solution should be in the file user/primes.c.

user/primes.c 文件中,利用管道和进程间通信的机制实现一个基于质数筛法(埃拉托斯特尼筛法)的程序。

Your goal is to use pipe and fork to set up the pipeline. The first process feeds the numbers 2 through 35 into the pipeline. For each prime number, you will arrange to create one process that reads from its left neighbor over a pipe and writes to its right neighbor over another pipe. Since xv6 has limited number of file descriptors and processes, the first process can stop at 35.

补充:

埃拉托斯特尼筛法(Sieve of Eratosthenes)是一种用于寻找一定范围内所有质数的简单且高效的算法。这个算法的基本思想是从小到大逐个筛去合数,最终剩下的就是质数。

算法步骤如下:

  1. 首先,创建一个包含从2到某个给定最大数的所有整数的列表。
  2. 从第一个素数2开始,将其所有的倍数(除了2本身)标记为合数(非质数)。
  3. 然后,选择下一个未标记的数,即下一个未被排除的素数,重复步骤2,直到没有未标记的数为止。

这个算法的主要思路在于利用倍数的概念,通过不断地排除合数,最终得到剩下的就是质数。

例如,假设我们要找出小于等于 30 的所有质数:

  • 首先,我们列出 2 到 30 的所有数。
  • 从 2 开始,我们标记 2 的所有倍数(除了2本身),即4、6、8、10、12、14、16、18、20、22、24、26、28 和 30。
  • 接下来,我们选择下一个未标记的数 3,然后标记 3 的所有倍数(除了3本身),即6、9、12、15、18、21、24、27 和 30。
  • 然后继续这个过程,选择下一个未标记的数 5,然后标记 5 的所有倍数(除了5本身),即10、15、20、25 和 30。
  • 最后,选择下一个未标记的数 7,然后标记 7 的所有倍数(除了7本身),即14和28。

最终剩下的未被标记的数就是质数:2、3、5、7、11、13、17、19、23和29。

思路:第一个子进程输入2~35。所有的子进程都是从父进程读取数据,然后将读到的一个数据打印出来,将所有读到的不是它倍数 的数据传递给自己的子进程。

MIB 6.1810实验Xv6 and Unix utilities(4)primes_子进程

 

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

#define READ 0
#define WRITE 1

void function(int num[],int size){
    if(size==0)return;
    int p[2];
    pipe(p);
    int pid=fork();
    if(pid>0){
        close(p[READ]);
        for(int i=0;i<size;i++){
            write(p[WRITE],&num[i],sizeof(num[i]));
        }
        close(p[WRITE]);
        wait(0);
    }else{
        close(p[WRITE]);
        int numc[34];
        int index=0;
        int tmp,min;
        while(read(p[READ],&tmp,sizeof(tmp))){
            if(index==0){
                min=tmp;
                printf("prime %d\n",min);
                index++;
            }
            if(tmp%min!=0){
                numc[index-1]=tmp;
                index++;
            }
        }
        close(p[READ]);
        function(numc,index-1);
        exit(0);
    }
}

int main(int argc, char *argv[])
{
    int num[34];
    int index = 0;
    for(int i=2;i<=35;i++){
        num[index++]=i;
    }
    function(num,34);
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.