6.s081 lab1

文档:

课程介绍 · 6.S081 All-In-One (dgs.zone)

网课:6.S081 / Fall 2020 [麻省理工操作系统 - 2020 年秋季][中英文字幕]_哔哩哔哩_bilibili

1.sleep

main的第一个参数一般是函数名,第二个才是参数

而输入的参数是Ascii码,系统调用sleep需要的是数值,因此需要转换

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

int 
main(int argc, char *argv[]) 
{
  if (argc != 2) {
    fprintf(2, "Usage: sleep <number>n");
    exit(1);
  }

  int i = *argv[1] - '1';
  sleep(i);
  exit(0);
}

2.pingpong

考验对管道的理解

错误:第一次写的时候,不知道pipe(p1)后,p1[0]为读入端,p1[1]为写入端。也就是说p1[0]、p1[1]的分工是被定死了的

这里close是一种习惯,当一个进程有太多管道的时候,可能会爆掉。比如xv6的每个进程最多只能打开16个文件描述符

read(p1[0], buf, n) 是从管道p1[0]中读取n个字节到buf,并返回实际读取的字节数。

因此可以使用 read(p1[0], buf, n) == n 来判断是否顺利读入

write(p1[1], buf, n)  同理

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

int main(int argc, char *argv[]){
	if(argc > 1){
		fprintf(2, "Usage: pingpongn");
		exit(1);
	}
	int p1[2], p2[2];
	pipe(p1);
	pipe(p2);
	char buf[1];
	if(fork() == 0){  //son should read
		buf[0] = '0';
		close(p1[0]);
		close(p2[1]);
		if(read(p2[0], buf, 1) == 1){
			close(p2[0]);
			printf("%d: received pongn", getpid());
		}
		write(p1[1], buf, 1);
		close(p1[1]);
	}
	else{
		buf[0] = '1';
		close(p1[1]);
		close(p2[0]);
		write(p2[1], buf, 1);
		close(p2[1]);
		if(read(p1[0], buf, 1) == 1){
			close(p1[0]);
			printf("%d: received pingn",getpid());
		}
	}
	exit(0);
}

3. primes

错误:把函数定义在main()之后,导致编译出错

main()函数进行第一次fork,父进程通过管道向子进程传递2~35。子进程调用递归。

递归的第一件事是检查其父进程是否通过管道传递数字,如果没有,说明递归结束。

如果有,那么传递的第一个数字i一定是质数(这些数都是不能被比它小的数字整除的),将其打印。

然后进行fork(),本进程进行筛选,将不能被i整除的数字传递给子进程,子进程调用递归

进程1->进程2:  传递      2~35

进程2:打印2,进程2->进程3 传递:  3~35                  筛掉能被2整除的数,传递给进程3  

进程3:打印3,进程3->进程4 传递:  5~35(不能被2、3整除)  筛掉能被3整除的数,传递给4

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

void ff(int p[]){
	close(p[1]);
	int i;
	// finish 2~35
	if(read(p[0], &i, sizeof(i)) == 0){
		close(p[0]);
		exit(0);
	}
	printf("prime %dn",i);
	int num, newp[2];
	pipe(newp);
	//son recursion
	if(fork() == 0){
		close(p[0]);
		close(newp[1]);
		ff(newp);
	}
	//parent output for son
	else{
		close(newp[0]);
		// get digit from its parent
		while(read(p[0], &num, sizeof(num)) != 0){
			//sift digit, and send to son
			if(num % i != 0)
				write(newp[1], &num, sizeof(num)); 
		}
		close(p[0]);
		close(newp[1]);
		wait(0);
	}
	exit(0);
}

int main(int argc, char *argv[]){
	//need not input
	if(argc > 1){          
		fprintf(2, "Usage: primesn");
		exit(1);
	}
	int p[2];
	pipe(p);
	
	//son
	if(fork() == 0){
		close(p[1]);
		ff(p);
	}
	//parent
	else{
		close(p[0]);
		for(int i = 2; i <= 35; i++){
			write(p[1], &i, sizeof(i));
		}
		close(p[1]);
		wait(0);
	}
	exit(0);
}

4. find

错误:

        在把目录名加入到buf后面的时候,一开始没想到用p,写成

buf[strlen(buf)] = '/';

memmove(buf + strlen(buf), de.name, DIRSIZ);

buf[ strlen(buf) ] = 0;

        这是因为没有想清楚,这是个dfs,while中的每个文件名相当于多叉树的一个分叉,走出去一步后应该撤销,再走另一分叉。buf[ strlen(buf) ] = 0;显然只是在结尾加个0,buf会成为当前目录下所有文件名的拼接。path name1 name2 name3

        应该使用p记录当前结点的path,一次循环结束后,memove把name2复制到当前path之后,而不是name1之后。然后再加0,这样即使name1很长,也因为加了0不影响

p指向'/'后一位                                           path/aaaaaaaa

memove(p, de.name, strlen(de.name))    path/bbbaaaaa

p[strlen(de.name)]=0                                path/bbb0aaaa

主要的问题是对很多全局变量不清楚

struct stat st;  fstat(fd, &st) 是将fd的信息存到结构体st中

struct dirent de; 

while(read(fd, &de, sizeof(de)) == sizeof(de)) 是遍历fd下的每个文件, 将fd中的某个文件读入到结构体de。de.name是文件名

stat的type属性:T_FILE为文件,T_DIR为目录

疑问:open(path, 0)的path是整个读进去,还是读到0为止

思路:dfs

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

void find(char *path, char *target){
	char buf[256], *p;
	int fd;
	struct dirent de;
	struct stat st;
	//打开path
	if((fd = open(path, 0)) < 0){
		fprintf(2, "find: cannot open %sn", path);
		return;
	}
	// 调用 fstat 将 fd 对应的文件信息记录在 st 中
	if(fstat(fd, &st) < 0){
		fprintf(2, "find: cannot stat %sn", path);
		return;
	}
	
	switch(st.type){
	// st.type 为文件时直接返回即可
	case T_FILE:
		if(strcmp(path + strlen(path) - strlen(target), target) == 0){
			printf("%sn", path);
		}
		break;
    //若为目录,则使用DFS,遍历当前目录下的每一个文件或目录,调用find不断递归,直到找到target
	case T_DIR:
		if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
			printf("find: path too longn");
			break;
		}
		strcpy(buf, path);
		p = buf + strlen(buf);
		*p++ = '/';
		while(read(fd, &de, sizeof(de)) == sizeof(de)){
			if(de.inum == 0)
				continue;
			if(strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
				continue;
            // 将 de.name 拷贝到 p 中
			memmove(p, de.name, strlen(de.name));
            //设置路径的结束符,因为buf要递归传给下一步作为path
			p[strlen(de.name)] = 0;
			find(buf, target);
		}
		break;
	}
	close(fd);
}

int main(int argc, char *argv[]){
	if(argc < 3){
		exit(0);
	}
	char target[256];
//自动在输入的目标前加一个‘/’
	target[0] = '/';
	strcpy(target + 1, argv[2]);
	find(argv[1], target);
	exit(0);
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>