Primes
#include "../kernel/types.h"#include "../user/user.h"#define MSGSIZE 36#define ONE '1'#define ZERO '0'void prime(int pipe_read, int pipe_write) {char buf[MSGSIZE];int val = 0;read(pipe_read, buf, MSGSIZE);for (int i = 0;i < MSGSIZE; i++) {if (buf[i] == ONE) {val = i;break;}}if (val == 0) {exit(0);}printf("prime %d\n", val);buf[val] = ZERO;for(int i = 0; i < MSGSIZE; i++) {if(i % val == 0) {buf[i] = ZERO;}}int pid = fork();if (pid > 0) {write(pipe_write, buf, MSGSIZE);wait(0);} else if (pid == 0) {prime(pipe_read, pipe_write);}exit(0);}int main (int argc, char* argv[]) {int fd[2];pipe(fd);char buf[MSGSIZE];for (int i = 0; i < MSGSIZE; i++) {buf[i] = ONE;}int pid = fork();if (pid > 0) {buf[0] = ZERO;buf[1] = ZERO;write(fd[1], buf, MSGSIZE);wait(0);} else if (pid == 0) {prime(fd[0], fd[1]);wait(0);}exit(0);}
素数筛法,要记住,fork函数后,一般要一个if-else分为父进程和子进程要执行的操作。
Find
#include "../kernel/types.h"#include "../kernel/stat.h"#include "../user/user.h"#include "../kernel/fs.h"char *fmtname(char *path) {static char buf[DIRSIZ + 1];char *p;// Find first character after last slash.for (p = path + strlen(path); p >= path && *p != '/'; p--);p++;// Return blank-padded name.if (strlen(p) >= DIRSIZ)return p;memmove(buf, p, strlen(p));memset(buf + strlen(p), 0, DIRSIZ - strlen(p));return buf;}voidfind(char *path, char *target) {char buf[512], *p;int fd;struct dirent de;struct stat st;if ((fd = open(path, 0)) < 0) {fprintf(2, "ls: cannot open %s\n", path);return;}if (fstat(fd, &st) < 0) {fprintf(2, "ls: cannot stat %s\n", path);close(fd);return;}if (strcmp(fmtname(path), target) == 0) {printf("%s\n", path);}switch (st.type) {case T_FILE:break;case T_DIR:if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {printf("ls: path too long\n");break;}strcpy(buf, path);p = buf + strlen(buf); //p为一个指针,指向buf(path)的末尾*p++ = '/';while (read(fd, &de, sizeof(de)) == sizeof(de)) {/*** 因为每个目录的子目录其实都有. 和 .. ,这样做是为了防止死循环*/if (de.inum == 0 || (strcmp(de.name, ".") == 0 || (strcmp(de.name, "..") == 0)))continue;memmove(p, de.name, DIRSIZ); // 把de.name拼接在p后面p[DIRSIZ] = 0; // p之前是在 '/' 处,现在[DIRSIZ] 表示向后移了DIRSIZ的位置find(buf, target);}break;}close(fd);}intmain(int argc, char *argv[]) {if (argc == 1) {printf("错误\n");exit(0);}if (argc == 2) {find(".", argv[2]);exit(0);}find(argv[1], argv[2]);exit(0);}
xargs
要点:对于管道符左右两边的命令,如果加了xargs,执行完左边的命令的输出,会自动作为后面命令初始read的标准输入。
#include "../kernel/types.h"#include "../kernel/param.h"#include "../kernel/stat.h"#include "../user/user.h"#include "../kernel/fs.h"#define MSGSIZE 16// echo hello too | xargs echo byeintmain(int argc, char *argv[]) {sleep(20); // 等待管道符前面的命令执行完// Q1 怎么获取前一个命令的标准化输出(即此命令的标准化输入)呢?char buf[MSGSIZE];read(0, buf, MSGSIZE);// Q2 如何获取到自己的命令行参数?char *xargv[MSGSIZE];int xargc = 0;for (int i = 1; i < argc; ++i) {xargv[xargc] = argv[i];xargc++;}char *p = buf;for (int i = 0;i < MSGSIZE; i++) {if (buf[i] == '\n') {int pid = fork();if (pid > 0) {p = &buf[i + 1];wait(0);} else {// Q3 如何使用exec去执行命令?buf[i] = 0;xargv[xargc] = p;xargc++;xargv[xargc] = 0;exec(xargv[0], xargv);exit(0);}}}wait(0);exit(0);}
- 对于fork函数来说,fork之后,父子进程的资源是一个相对独立的整体
- 在子进程没执行完成前,进程内的所有资源都是私有的,当执行完后,才会把变化合进父进程
- 对于子进程来说,修改基本数据类型无法同步修改,而修改char[] 或 * 等则可以。
