lab1-util
启动xv6(简单)
下载代码并切换分支:
$ git clone git://g.csail.mit.edu/xv6-labs-2021
Cloning into 'xv6-labs-2021'...
...
$ cd xv6-labs-2021
$ git checkout util
Branch 'util' set up to track remote branch 'util' from 'origin'.
Switched to a new branch 'util'编译运行,make编译,qemu模拟
$ make qemu # <C-a> + x退出
sleep(简单)
实现unixsleep程序,sleep程序可以按照用户指定的时间停止程序。
程序需要在 user/sleep.c中实现,文件未创建,我们将user/echo.c拷贝成我们的模板:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h" # 三者引用关系不能交换顺序
int main(int argc, char *argv[])
{
exit(0);
}在user.h中已经定义了sleep函数,这里直接使用
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h" // 会使用 user.h 中的 atoi 函数
int main(int argc, char *argv[])
{
// 如果用户未指定sleep时间,那么sleep 一秒
if (argc < 2)
{
printf("Require sleep time, use: sleep 1");
exit(1);
}
int sleep_time = atoi(argv[1]);
printf("(nothing happens for a little while)");
sleep(sleep_time);
exit(0);
}
将sleep程序写入MakeFile中的UPROGS里,
UPROGS=\
...
$U/_sleep\ # here!!!测试程序:
$ ./grade-lab-util sleep
pingpong(简单)
使用UNIX系统调用在两个进程之间通过一对管道“乒乓”一个字节,每个方向一个管道。
- 父进程应该向子进程发送一个字节
- 子进程应该输出:
<pid>: received ping“,其中<pid>是它的进程号,把这个字节写在管道上给父进程,然后退出 - 父进程应该从子进程读取字节,打印
<pid>: received pong,然后退出。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char* argv[]){
// 0用于读,1用于写
int p2c[2], c2p[2]; // 两个管道
pipe(p2c); // 父进程 -> 子进程 的管道
pipe(c2p); // 子进程 -> 父进程 的管道
if(fork() != 0){
// I'm Parent
write(p2c[1], "!", 1); // send to child
char buf;
read(c2p[0], &buf, 1); // read from child
printf("%d: received pong!\n", getpid());
wait(0);
}
else{
// I'm Child
char buf;
read(p2c[0], &buf, 1); // read from parent
printf("%d: received ping!\n", getpid());
write(c2p[1], "!", 1); // send to child
}
exit(0);
}primes(中难)
使用管道实现求质数,看不懂要干啥的看这里:Bell Labs and CSP Threads
基本原理还是埃式筛,直接原来是开一个数组存bool,现在将开一个数组存子进程
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
/**
* p = get a number from left neighbor
* print p
* loop:
* n = get a number from left neighbor
* if (p does not divide n)
* send n to right neighbor
*/
void prime(int msg){
int n;
// no message
if(read(msg, &n, 4) == 0)exit(0);
printf("%d is prime\n", n);
int pip[2]; // pipe
pipe(pip);
int pid = fork();
// create a child process and send message to the child,
// like what we do in main() function
if (pid != 0)
{
close(pip[0]);
// i'm parent
int next_num = -1;
// get all the number from left neighbor
while (read(msg, &next_num, 4) != 0)
{
if (next_num % n != 0)
{
write(pip[1], &next_num, 4);// send it to the right
}
}
close(pip[1]);
wait(0);
}
else
{
// i'm child
close(pip[1]);
prime(pip[0]);
close(pip[0]);
}
}
int main(int argc, char* argv[]){
int pip[2]; // pipe
pipe(pip);
int pid = fork();
if(pid != 0){
// root
close(pip[0]); // do not read
for (int i = 2; i <= 35; i++)
{
write(pip[1], &i, 4); // send message to childs
}
close(pip[1]);// write done
wait(0);
}else{
// first child
close(pip[1]); // i won't write
prime(pip[0]); // read
close(pip[0]); //read done
}
exit(0);
}这里的main方法和prime几乎是等价的
可以先改变一下题目要求:
main 函数生成 2-35 之间的数字,将其发送给子进程,让其输出
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
void prime(int msg)
{
int n;
while ((read(msg, &n, 4) != 0))
{
printf("%d is prime\n", n);
}
}
int main(int argc, char* argv[]){
int pip[2]; // pipe
pipe(pip);
int pid = fork();
if(pid != 0){
// root
close(pip[0]); // do not read
for (int i = 2; i <= 35; i++)
{
write(pip[1], &i, 4); // send message to childs
}
close(pip[1]);// write done
wait(0);
}else{
// first child
close(pip[1]); // i won't write
prime(pip[0]); // read
close(pip[0]); //read done
}
exit(0);
}
然后在改编一下,子进程会拿到第一个消息 n 后,只会输出与之不互质的
void prime(int msg)
{
int n;
if (read(msg, &n, 4) == 0)
exit(0);
while ((read(msg, &n, 4) != 0))
{
if (msg % n != 0)
printf("%d is prime\n", n);
}
}然后应该很容易想到如何送给子进程了