Primes

  1. #include "../kernel/types.h"
  2. #include "../user/user.h"
  3. #define MSGSIZE 36
  4. #define ONE '1'
  5. #define ZERO '0'
  6. void prime(int pipe_read, int pipe_write) {
  7. char buf[MSGSIZE];
  8. int val = 0;
  9. read(pipe_read, buf, MSGSIZE);
  10. for (int i = 0;i < MSGSIZE; i++) {
  11. if (buf[i] == ONE) {
  12. val = i;
  13. break;
  14. }
  15. }
  16. if (val == 0) {
  17. exit(0);
  18. }
  19. printf("prime %d\n", val);
  20. buf[val] = ZERO;
  21. for(int i = 0; i < MSGSIZE; i++) {
  22. if(i % val == 0) {
  23. buf[i] = ZERO;
  24. }
  25. }
  26. int pid = fork();
  27. if (pid > 0) {
  28. write(pipe_write, buf, MSGSIZE);
  29. wait(0);
  30. } else if (pid == 0) {
  31. prime(pipe_read, pipe_write);
  32. }
  33. exit(0);
  34. }
  35. int main (int argc, char* argv[]) {
  36. int fd[2];
  37. pipe(fd);
  38. char buf[MSGSIZE];
  39. for (int i = 0; i < MSGSIZE; i++) {
  40. buf[i] = ONE;
  41. }
  42. int pid = fork();
  43. if (pid > 0) {
  44. buf[0] = ZERO;
  45. buf[1] = ZERO;
  46. write(fd[1], buf, MSGSIZE);
  47. wait(0);
  48. } else if (pid == 0) {
  49. prime(fd[0], fd[1]);
  50. wait(0);
  51. }
  52. exit(0);
  53. }

素数筛法,要记住,fork函数后,一般要一个if-else分为父进程和子进程要执行的操作。

Find

  1. #include "../kernel/types.h"
  2. #include "../kernel/stat.h"
  3. #include "../user/user.h"
  4. #include "../kernel/fs.h"
  5. char *
  6. fmtname(char *path) {
  7. static char buf[DIRSIZ + 1];
  8. char *p;
  9. // Find first character after last slash.
  10. for (p = path + strlen(path); p >= path && *p != '/'; p--);
  11. p++;
  12. // Return blank-padded name.
  13. if (strlen(p) >= DIRSIZ)
  14. return p;
  15. memmove(buf, p, strlen(p));
  16. memset(buf + strlen(p), 0, DIRSIZ - strlen(p));
  17. return buf;
  18. }
  19. void
  20. find(char *path, char *target) {
  21. char buf[512], *p;
  22. int fd;
  23. struct dirent de;
  24. struct stat st;
  25. if ((fd = open(path, 0)) < 0) {
  26. fprintf(2, "ls: cannot open %s\n", path);
  27. return;
  28. }
  29. if (fstat(fd, &st) < 0) {
  30. fprintf(2, "ls: cannot stat %s\n", path);
  31. close(fd);
  32. return;
  33. }
  34. if (strcmp(fmtname(path), target) == 0) {
  35. printf("%s\n", path);
  36. }
  37. switch (st.type) {
  38. case T_FILE:
  39. break;
  40. case T_DIR:
  41. if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
  42. printf("ls: path too long\n");
  43. break;
  44. }
  45. strcpy(buf, path);
  46. p = buf + strlen(buf); //p为一个指针,指向buf(path)的末尾
  47. *p++ = '/';
  48. while (read(fd, &de, sizeof(de)) == sizeof(de)) {
  49. /**
  50. * 因为每个目录的子目录其实都有. 和 .. ,这样做是为了防止死循环
  51. */
  52. if (de.inum == 0 || (strcmp(de.name, ".") == 0 || (strcmp(de.name, "..") == 0)))
  53. continue;
  54. memmove(p, de.name, DIRSIZ); // 把de.name拼接在p后面
  55. p[DIRSIZ] = 0; // p之前是在 '/' 处,现在[DIRSIZ] 表示向后移了DIRSIZ的位置
  56. find(buf, target);
  57. }
  58. break;
  59. }
  60. close(fd);
  61. }
  62. int
  63. main(int argc, char *argv[]) {
  64. if (argc == 1) {
  65. printf("错误\n");
  66. exit(0);
  67. }
  68. if (argc == 2) {
  69. find(".", argv[2]);
  70. exit(0);
  71. }
  72. find(argv[1], argv[2]);
  73. exit(0);
  74. }

xargs

要点:对于管道符左右两边的命令,如果加了xargs,执行完左边的命令的输出,会自动作为后面命令初始read的标准输入。

  1. #include "../kernel/types.h"
  2. #include "../kernel/param.h"
  3. #include "../kernel/stat.h"
  4. #include "../user/user.h"
  5. #include "../kernel/fs.h"
  6. #define MSGSIZE 16
  7. // echo hello too | xargs echo bye
  8. int
  9. main(int argc, char *argv[]) {
  10. sleep(20); // 等待管道符前面的命令执行完
  11. // Q1 怎么获取前一个命令的标准化输出(即此命令的标准化输入)呢?
  12. char buf[MSGSIZE];
  13. read(0, buf, MSGSIZE);
  14. // Q2 如何获取到自己的命令行参数?
  15. char *xargv[MSGSIZE];
  16. int xargc = 0;
  17. for (int i = 1; i < argc; ++i) {
  18. xargv[xargc] = argv[i];
  19. xargc++;
  20. }
  21. char *p = buf;
  22. for (int i = 0;i < MSGSIZE; i++) {
  23. if (buf[i] == '\n') {
  24. int pid = fork();
  25. if (pid > 0) {
  26. p = &buf[i + 1];
  27. wait(0);
  28. } else {
  29. // Q3 如何使用exec去执行命令?
  30. buf[i] = 0;
  31. xargv[xargc] = p;
  32. xargc++;
  33. xargv[xargc] = 0;
  34. exec(xargv[0], xargv);
  35. exit(0);
  36. }
  37. }
  38. }
  39. wait(0);
  40. exit(0);
  41. }
  • 对于fork函数来说,fork之后,父子进程的资源是一个相对独立的整体
  • 在子进程没执行完成前,进程内的所有资源都是私有的,当执行完后,才会把变化合进父进程
  • 对于子进程来说,修改基本数据类型无法同步修改,而修改char[] 或 * 等则可以。