homework4
100%
cpu 4 + io-run 1 + block 5 + io-done 1 总时间 11,cpu:5, io:6
交换顺序后,io阻塞期间,系统同时执行CPU工作,总时间为7。交换顺序可以有效利用系统资源。
系统执行完I/O后执行CPU工作。
系统执行I/O同时执行CPU工作。
当 I/O 完成时, 发出它的进程不一定马上运行。相反,当时运行的进程一直运行。
CPU利用率显著提高。运行完一个刚刚完成I/O的进程,可以有效利用I/O阻塞时间,执行CPU工作。
指令:-s 2 -l 3:50,10:100
-I -IO_RUN_IMMEDIATE:I/O完成时,发出它的进程立刻运行io-done (Total time: 15)
-I-IO_RUN_LATER:I/O完成时,发出它的进程等待CPU工作完成后再运行。(Total time: 20)
-S SWITCH_ON_IO:进行I/O操作时,系统会切换到其他进程。(Total time: 20)
-S SWITCH_ON_END:进行I/O操作时,系统不会切换到其他进程。(Total time: 25)
homework5 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int main (int argc, char *argv[]) { int x = 100 ; int PID = fork(); if (PID < 0 ) { printf ("Fork failed\n" ); exit (1 ); } if (PID == 0 ) { x += 1 ; printf ("Child processx = %d\n" , x); exit (0 ); }else { wait(NULL ); x += 1 ; printf ("Parent process x = %d\n" , x); } }
子进程x变量是父进程x变量的副本,子进程是父进程的副本,包括代码段、数据段、堆和栈。
2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 int main () { int fd; const char *filepath = "example.txt" ; const char *text1 = "Hello, World Child!\n" ; const char *text2 = "Hello, world Parent\n" ; int file = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0644 ); int pid = fork(); if (pid < 0 ) { perror("fork" ); return 1 ; }else if (pid == 0 ){ if (file < 0 ) { perror("child open fail" ); exit (0 ); } int n = write(file, text1, strlen (text1)); if (n < 0 ) { perror("child write fail" ); exit (0 ); } close(file); printf ("child write %d bytes\n" , n); }else { if (file < 0 ) { perror("parent open fail" ); exit (0 ); } int n = write(file, text2, strlen (text2)); if (n < 0 ) { perror("parent write fail" ); exit (0 ); } close(file); printf ("parent write %d bytes\n" , n); } }
子进程和父进程都可访问open返回的文件描述符,并发写入文件时可能会出现竞争写入同一位置的情况。
3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main (int argc, char *argv[]) { int PID = fork(); if (PID < 0 ) { perror("fork" ); exit (1 ); } if (PID == 0 ) { printf ("hello\n" ); exit (0 ); }else { usleep(1000 ); printf ("goodbye\n" ); } }
4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 int main () { int rc = fork(); if (rc < 0 ) { fprintf (stderr , "fork failed\n" ); exit (1 ); } else if (rc == 0 ) { printf ("Child process (pid:%d)\n" , getpid()); char *envp[] = { "PATH=/bin" , NULL }; execle("/bin/ls" , "ls" , "-l" , NULL , envp); perror("exec" ); exit (1 ); } else { wait(NULL ); printf ("Parent process (pid:%d) waits for child to finish.\n" , getpid()); } return 0 ; }
execl():
原型: int execl(const char *path, const char *arg0, ..., (char *) NULL);
以参数列表形式传递程序路径及其参数,每个参数都是一个字符串。
最后一个参数必须是 NULL
,表示参数列表的结束。
例如:execl("/bin/ls", "ls", "-l", NULL);
execle():
原型: int execle(const char *path, const char *arg0, ..., (char *) NULL, char *const envp[]);
与 execl()
类似,但可以额外传递环境变量数组 envp[]
。
例如:char *envp[] = { "PATH=/bin", NULL }; execle("/bin/ls", "ls", "-l", NULL, envp);
execlp():
原型: int execlp(const char *file, const char *arg0, ..., (char *) NULL);
与 execl()
类似,但是程序文件名可以不带路径,会根据 PATH
环境变量搜索可执行文件。
例如:execlp("ls", "ls", "-l", NULL);
execv():
原型: int execv(const char *path, char *const argv[]);
以参数数组形式传递程序路径及其参数,参数数组以 NULL
结束。
例如:char *args[] = { "ls", "-l", NULL }; execv("/bin/ls", args);
execvp():
原型: int execvp(const char *file, char *const argv[]);
与 execv()
类似,但是程序文件名可以不带路径,会根据 PATH
环境变量搜索可执行文件。
例如:char *args[] = { "ls", "-l", NULL }; execvp("ls", args);
execvP():
原型: int execvP(const char *file, const char *search_path, char *const argv[]);
与 execvp()
类似,但是可以指定搜索程序文件的路径 search_path
。
例如:char *args[] = { "ls", "-l", NULL }; execvP("/bin", "ls", args);
区别主要在于命令搜索路径,以及参数传递方式
5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int main (int argc, char *argv[]) { int PID = fork(); if (PID < 0 ) { printf ("Fork failed\n" ); exit (1 ); } if (PID == 0 ) { int res = wait(NULL ); printf ("Child pid: %d\n" , getpid()); printf ("Child wait return: %d\n" , res); exit (0 ); }else { int res = wait(NULL ); printf ("Parent wait return: %d\n" , res); } }
父进程wait返回子进程id,子进程wait返回-1。
6 等待特定的子进程结束。
7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int main () { printf ("Parent process: Hello!\n" ); int rc = fork(); if (rc < 0 ) { fprintf (stderr , "Fork failed\n" ); exit (1 ); } else if (rc == 0 ) { printf ("Child process: Closing stdout and trying to print...\n" ); close(STDOUT_FILENO); printf ("This should not be printed\n" ); printf ("Child process is done\n" ); exit (0 ); } else { int wc = wait(NULL ); printf ("Parent process: Child process terminated\n" ); } return 0 ; }
子进程printf无法打印至终端。
8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 int main () { int pipefd[2 ]; pid_t pid1, pid2; if (pipe(pipefd) == -1 ) { perror("pipe" ); exit (EXIT_FAILURE); } pid1 = fork(); if (pid1 < 0 ) { perror("fork" ); exit (EXIT_FAILURE); } else if (pid1 == 0 ) { close(pipefd[0 ]); dup2(pipefd[1 ], STDOUT_FILENO); close(pipefd[1 ]); execlp("echo" , "echo" , "Hello from child 1" , NULL ); perror("execlp" ); exit (EXIT_FAILURE); } else { pid2 = fork(); if (pid2 < 0 ) { perror("fork" ); exit (EXIT_FAILURE); } else if (pid2 == 0 ) { close(pipefd[1 ]); dup2(pipefd[0 ], STDIN_FILENO); close(pipefd[0 ]); execlp("grep" , "grep" , "child" , NULL ); perror("execlp" ); exit (EXIT_FAILURE); } else { close(pipefd[0 ]); close(pipefd[1 ]); wait(NULL ); wait(NULL ); } } return 0 ; }