MIT XV6 - 1.3 Lab: Xv6 and Unix utilities - primes

接上文 MIT XV6 - 1.2 Lab: Xv6 and Unix utilities - pingpong

primes

继续实验,实验介绍和要求如下 (原文链接 译文链接) :

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.

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.

Some hints:

  • Be careful to close file descriptors that a process doesn’t need, because otherwise your program will run xv6 out of resources before the first process reaches 35.
  • Once the first process reaches 35, it should wait until the entire pipeline terminates, including all children, grandchildren, &c. Thus the main primes process should only exit after all the output has been printed, and after all the other primes processes have exited.
  • Hint: read returns zero when the write-side of a pipe is closed.
  • It’s simplest to directly write 32-bit (4-byte) ints to the pipes, rather than using formatted ASCII I/O.
  • You should create the processes in the pipeline only as they are needed.
  • Add the program to UPROGS in Makefile.

大致意思呢,参考 Unix pipes的创造者,大佬Doug McIlroyBell Labs and CSP Threads,基于多进程和管道来筛选一定范围内的素数.

在这里插入图片描述
什么意思呢,每个进程呢就像一个过滤器,把自己处理不了的数据扔给下一级,我是这么理解的啊,这样可能更符合这个实验?

地铁路上想好了怎么写,回来一遍过

/*
 * Prime Number Sieve using Pipes
 * 
 * This program implements the Sieve of Eratosthenes algorithm using pipes and processes
 * to find prime numbers concurrently. The algorithm works as follows:
 * 
 * 1. Each process represents a prime number and filters out its multiples
 * 2. Numbers are passed through pipes between processes
 * 3. Each process reads numbers from its left pipe and writes non-multiples to its right pipe
 * 
 * Process Communication Flow:
 * 
 * Process 1 (2) -> Process 2 (3) -> Process 3 (5) -> Process 4 (7) -> ...
 *    [pipe1]         [pipe2]         [pipe3]          [pipe4]
 * 
 * Each process:
 * 1. Reads numbers from left pipe
 * 2. If number is not divisible by its prime, passes it to right pipe
 * 3. Creates new child process for first number it receives
 * 
 * Example flow for numbers 2-10:
 * 
 * Time   Process 1    Process 2    Process 3    Process 4
 * ---------------------------------------------------------
 * t0      reads 2      -            -            -
 * t1      sends 3      reads 3      -            -
 * t2      sends 5      sends 5      reads 5      -
 * t3      sends 7      sends 7      sends 7      reads 7
 * t4      sends 9      reads 9      -            -
 * 
 * Note: Numbers 4, 6, 8, 10 are filtered out by Process 1 (multiples of 2)
 *       Numbers 9 is filtered out by Process 2 (multiple of 3)
 *       Only prime numbers reach their corresponding processes
 */

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

// Constants for prime number calculation
#define START_PRIME 2        // First prime number to start with
#define MAX_PRIMES 35       // Maximum number to check for primes

// Pipe file descriptor constants
#define PIPE_INVALID -1      // Invalid pipe descriptor
#define PIPE_READ 0          // Read end of pipe
#define PIPE_WRITE 1         // Write end of pipe

/**
 * Prints a prime number to the console
 * @param n The prime number to print
 */
void print_prime(int n) { printf("prime %d\n", n); }

/**
 * Safely closes a pipe file descriptor if it's valid
 * @param p The pipe file descriptor to close
 */
void close_pipe_if_valid(int p) {
  if (p != PIPE_INVALID) {
    close(p);
  }
}

/**
 * Delivers a number through the pipe system and creates new processes for primes
 * @param n The number to process
 * @param pipe_left The left pipe for receiving numbers
 */
void deliver_prime(int n, int pipe_left[2]) {
  // If pipe is not initialized, create it and fork a new process
  if (pipe_left[PIPE_WRITE] == PIPE_INVALID) {
    int ret = pipe(pipe_left);
    if (ret < 0) {
      exit(1);
    }

    ret = fork();
    if (ret == 0) {
      // Child process
      close_pipe_if_valid(pipe_left[PIPE_WRITE]);

      // Print the prime number this process represents
      print_prime(n);

      // Initialize right pipe for passing numbers to next process
      int pipe_right[2] = {PIPE_INVALID, PIPE_INVALID};
      int received_number = 0;

      // Read numbers from left pipe and filter them
      while (read(pipe_left[PIPE_READ], &received_number,
                  sizeof(received_number)) > 0) {
        // Skip numbers that are multiples of current prime
        if (received_number % n == 0) {
          continue;
        }

        // Pass non-multiples to next process
        deliver_prime(received_number, pipe_right);
      }

      // Clean up pipes
      close_pipe_if_valid(pipe_left[PIPE_READ]);
      close_pipe_if_valid(pipe_right[PIPE_READ]);
      close_pipe_if_valid(pipe_right[PIPE_WRITE]);

      // Wait for child process to complete
      wait(0);
      exit(0);
    } else if (ret > 0) {
      // Parent process continues
    } else {
      printf("fork error, current index: %d\n", n);
      exit(1);
    }
  } else {
    // printf("deliver_prime: %d\n", n);
    // Write number to pipe
    if (write(pipe_left[PIPE_WRITE], &n, sizeof(n)) <= 0) {
      exit(1);
    }
  }
}

/**
 * Main function that initiates the prime number calculation
 * @param argc Number of command line arguments
 * @param argv Command line arguments
 * @return 0 on successful execution
 */
int main(int argc, char *argv[]) {
  // Initialize pipe for first process
  int p[2] = {PIPE_INVALID, PIPE_INVALID};

  // Print the first prime number
  print_prime(START_PRIME);

  // Process numbers from START_PRIME + 1 to MAX_PRIMES
  for (int i = START_PRIME + 1; i <= MAX_PRIMES; i++) {
    // Skip multiples of START_PRIME
    if (i % START_PRIME == 0) {
      continue;
    }

    // Process the number through the pipe system
    deliver_prime(i, p);
  }

  // Clean up pipes
  close(p[PIPE_READ]);
  close(p[PIPE_WRITE]);

  // Wait for child process to complete
  wait(0);

  return 0;
}

实验结果

make qemu
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -global virtio-mmio.force-legacy=false -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0

xv6 kernel is booting

hart 1 starting
hart 2 starting
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

他实验中提到一点 Since xv6 has limited number of file descriptors and processes, the first process can stop at 35.,于是我把 MAX_PRIMES改成了100并加了一些错误日志,试一下什么时候会"资源耗尽"。

make qemu
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -global virtio-mmio.force-legacy=false -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0

xv6 kernel is booting

hart 2 starting
hart 1 starting
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
prime 37
prime 41
pipe error, current index: 43
$ 

为什么是43?留个坑吧…

### 回答1:xv6是一个基于Unix操作系统,它是一个教学用途的操作系统,旨在教授操作系统的基本概念和实现。它是在MIT的x86架构上开发的,包括了Unix的一些基本功能,如进程管理、文件系统、内存管理等。xv6的源代码是公开的,可以用于学习和研究。 Unix utilitiesUnix操作系统中的一些基本工具,如ls、cd、cp、mv、rm等。这些工具可以帮助用户管理文件和目录,执行各种操作。这些工具的实现是基于Unix的系统调用,可以通过编写C程序来调用这些系统调用实现相应的功能。这些工具是Unix操作系统的基础,也是其他操作系统的参考。 ### 回答2: lab: xv6 and unix utilities 实验是一项旨在帮助学生深入理解操作系统Unix 工具使用的实验。该实验分为两个部分,第一部分教授学生如何构建和运行 xv6 操作系统;第二部分则重点教授 Unix 工具的使用。 在 xv6 操作系统部分,学生将学习到操作系统内核的基本结构和实现原理。实验将引导学生理解内存管理、进程调度、系统调用等关键操作系统概念。此外,学生还将学习如何编写简单的 shell 以及如何通过修改 xv6 内核代码来实现新的系统调用和功能。 在 Unix 工具部分,学生将探索 Unix 系统中广泛使用的常见工具。这些工具包括 vi 编辑器、grep、awk、sed 等。实验将介绍这些工具的基本使用方法以及它们在处理文本和数据时的实际应用。这部分实验还将让学生深入了解 shell 和 shell 脚本的编写,帮助他们在 Unix 环境中轻松地编写脚本和自动化任务。 lab: xv6 and unix utilities 实验对计算机科学专业的学生具有重要意义。通过完成这个实验,学生将建立起对操作系统Unix 工具的深入理解,为他们成为一名优秀的软件工程师奠定坚实的基础。同时,这个实验还将为学生提供实践经验,让他们能够将所学知识应用到真实的软件开发和运维中。 ### 回答3Lab: xv6 and Unix Utilities是一个计算机科学领域的实验,旨在让学生深入了解Unix操作系统以及操作系统本身的自我管理机制。在这个实验中,学生需要从零开始构建一个类似于Unix操作系统,在这个操作系统中,学生需要设计一些基本命令,例如ls,cat,grep等等,并且将它们与系统的底层API结合起来,以实现各种功能。此外,学生还需要了解和探索xv6这个开发工具,它是一个轻量级基于Unix操作系统实现,具有一定的可移植性和简洁性,因此,它可以作为一个基础框架来实现一个完整的Unix操作系统。 这个实验的目标是让学生了解Unix的基本命令结构和API,以及操作系统内部的一些基本机制,例如进程管理,文件系统交互以及进程通信等等。此外,通过实现这些命令,学生还可以学到一些基本的C语言编程技能,例如文件操作,字符串处理以及进程管理等等。还可以学习到如何使用Git等版本控制工具,以及如何进行调试和测试代码的技巧。 在整个实验过程中,学生需要有较强的自我管理能力和综合运用能力,因为在实现这些命令的同时,他们还需要和其他团队成员进行交流和合作,以及不断改进和完善他们的代码。总之,这个实验是一个非常有趣且富有挑战性的计算机科学课程,通过完成这个实验,学生可以更好地了解操作系统的构造和运作机制,以及如何设计和开发高效的系统级应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值