產生新的程序:fork() (2/4) fork()回傳時,若成功 若fork()失敗,則回傳-1 新子程序將被加入於系統中 子程序與父程序擁有一模一樣的記憶體內容 程式機器碼、程序所有資料、程序堆疊(stack)、程序heap、環境變數等 子程序與父程序不同的屬性有:PID、資源使用率、CPU計時器、待處理號誌、應用程式 計時器 (重設) fork()回傳值 在父程序,回傳值為新子程序的PID 在子程序,回傳值為0 可做為分工合作時,不同的程式碼段落 父程序程式碼 vs. 子程序的程式碼 (在同一支程式內) 若fork()失敗,則回傳-1
若fork()成功,父程序與子程序均從此敘述繼續執行 fork() 程式範例 fork() (3/4) 若fork()成功,父程序與子程序均從此敘述繼續執行 #include <stdio.h> #include <unistd.h> int main() { int var = 0; pid_t pid; pid = fork(); printf(“%d”, var); if(pid == 0) { /* child 執行 */ var = 1; } else if (pid > 0) { /* parent 執行 */ var = 2; } printf(“%d”, var) return 0;
fork()程式範例 fork()(4/4) 利用fork()的回傳值 (亦即pid)進行父程序與子程序各自需要完成任務的 程式碼區分 各程序的執行結果: 父程序:02 子程序:01 然而,系統並沒有限制兩個程序的執行順序 若fork()成功,執行結果可能為:0012, 0021, 0102, 或 0201 若fork()失敗,執行結果為:00
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan Lab 1: debugging fork() Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan Lab 1: debugging fork() When a program forks, gdb will continue to debug the parent process and the child process will run unimpeded. If you have set a breakpoint in any code which the child then executes, the child will get a SIGTRAP signal which (unless it catches the signal) will cause it to terminate. debugging the child process using touch commend (hint: put sleep after fork) debug child process instead of parent process (using “set follow-fork-mode child” http://sourceware.org/gdb/onlinedocs/gdb/Forks.html http://www.cnblogs.com/zhenjing/archive/2011/06/01/gdb_fork.html Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan lab 1: debugging fork() $gcc -g lab1-1.c $gdb a.out (gdb)b main /*set a breakpoint*/ (gdb)r /*run*/ (gdb)n /*next*/ (gdb)s /*step into*/ (gdb)p glob /*print*/ (gdb)display glob (gdb)c /*continue*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan lab 1: debugging fork() $gcc -g lab1-1.c $gdb a.out (gdb)l main /*list 10 lines of source code of main function*/ (gdb)b main /*set a breakpoint*/ (gdb)r /*run*/ (gdb)n /*next*/ (gdb)p globvar /*print*/ (gdb)c /*continue*/ (gdb)set globvar=11 /*Setting Variables*/ http://betterexplained.com/articles/debugging-with-gdb/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan lab 1: debugging fork() (gdb) set follow-fork-mode child (gdb) n ... (gdb) p pid /*child OR parent?*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan lab 1: debugging fork() (gdb) set follow-fork-mode child (gdb) n ... (gdb) p pid /*child OR parent?*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan lab 1: debugging fork() /*modify your program like... waiting = 1; if (fork()==0) while(waiting); ... */ $sudo gdb a.out (gdb) attach pid (gdb) set waiting=0 /*continue*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
將新的程式載入程序中:exec (2/5) exec若執行成功,原本記憶體的程序資料(機器碼、資料、堆疊、heap、 環境)均被新的程式資料取代。 因為原本呼叫exec的程式已經不存在,所以exec就不會回傳。 exec若執行不成功,函數將回傳-1到原本的程式並且會設定errno全域 變數記錄錯誤情況。
Lab 1 列印所有可註冊的signal #include <stdlib.h> #include <signal.h> #include <stdio.h> void sighandler(int signumber) { printf("get a signal named '%d', '%s'\n", signumber, sys_siglist[signumber]); } int main(int argc, char **argv) { int sig_exist[100]; int idx = 0; for (idx = 0; idx < 100; idx++) { if (signal(idx, sighandler) == SIG_ERR) {
Lab 1 列印所有可註冊的signal sig_exist[idx] = 0; } else { sig_exist[idx] = 1; for (idx = 0; idx < 100; idx++) { if (sig_exist[idx] == 1) printf("%2d %s\n", idx, sys_siglist[idx]); printf("my pid is %d\n", getpid()); printf("press any key to resume\n"); getchar();
Lab 1: results (MAC OS X) 1 Hangup 2 Interrupt 3 Quit 4 Illegal instruction 5 Trace/BPT trap 6 Abort trap 7 EMT trap 8 Floating point exception 10 Bus error 11 Segmentation fault 12 Bad system call 13 Broken pipe 14 Alarm clock 15 Terminated 16 Urgent I/O condition 18 Suspended 19 Continued 20 Child exited 21 Stopped (tty input) 22 Stopped (tty output) 23 I/O possible 24 Cputime limit exceeded 25 Filesize limit exceeded 26 Virtual timer expired 27 Profiling timer expired 28 Window size changes 29 Information request 30 User defined signal 1 31 User defined signal 2
Lab 1: results (Linux) 1 Hangup 2 Interrupt 3 Quit 4 Illegal instruction 5 Trace/breakpoint trap 6 Aborted 7 Bus error 8 Floating point exception 10 User defined signal 1 11 Segmentation fault 12 User defined signal 2 13 Broken pipe 14 Alarm clock 15 Terminated 16 Stack fault 17 Child exited 18 Continued 20 Stopped 21 Stopped (tty input) 22 Stopped (tty output) 23 Urgent I/O condition 24 CPU time limit exceeded 25 File size limit exceeded 26 Virtual timer expired 27 Profiling timer expired 28 Window changed 29 I/O possible 30 Power failure 31 Bad system call
Lab 1: results (Linux) 試試看 kill -4 pid 調整terminal window的大小
Lab2: segmentation fault 試試看”故意存取錯誤的記 憶體”
示意圖 父行程 子行程 子行程 stdout stdin
aio.c int count=0; void aioSigHandler(int sig, siginfo_t *si, void *ucontext) { count++; } int main(int argc, char **argv) { int i, ret; int start, end; struct sigaction sa; int fd; struct aiocb aiocb_ary[1000]; char buf[1000][4096]; memset(buf, 'a', 1000*4096); fd=open("./tmp",O_RDWR); sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_sigaction = aioSigHandler; if (sigaction(SIGUSR1, &sa, NULL) == -1)
aio.c perror("sigaction"); start = clock(); for(i=0; i<1000; i++) { aiocb_ary[i].aio_buf = &buf[i][0]; aiocb_ary[i].aio_fildes = fd; //stdin aiocb_ary[i].aio_nbytes = 4096; aiocb_ary[i].aio_offset = 4096*i; aiocb_ary[i].aio_sigevent.sigev_notify = SIGEV_SIGNAL; aiocb_ary[i].aio_sigevent.sigev_signo = SIGUSR1; if (aio_write(&aiocb_ary[i]) != 0) perror("aio_read"); } end = clock(); printf("aio time = %d/%ld sec\n", end - start, CLOCKS_PER_SEC); printf("I/O # = %d\n", count); for (i=0; i<100000; i++) ; printf("finish! I/O # = %d\n", count); return 0;
Pthead PI Rand不是reentrant function,如果一定要使用,記得用mutex包起 來 平行度越高也要計算得越快
Shared memory PI Rand不是reentrant function,但在process中可用乎?確保每個 process的random seed不一樣 平行度越高也要計算得越快