基礎操做系統-進程-併發程序設計

這學期感受最有難度的就是操做系統這門課了,之前Linux接觸的很少,雙學位跳級學習課程暫時尚未學完其中的基礎課。因此可能錯誤多一些。
併發

一、  相關頭文件函數

<unistd.h> <sys/types.h> <sys/wait.h> <stdio.h> <stdlib.h>學習

 

二、  函數說明測試

l  fork(創建一個新的進程)this

定義函數  pid_t fork(void);操作系統

函數說明  fork()會產生一個新的子進程,其子進程會複製父進程的數據與堆棧空間,並繼承父進程的用戶代碼,組代碼,環境變量、已打開的文件代碼、工做目錄和資源限制等。線程

返回值    若是fork()成功則在父進程會返回新創建的子進程代碼(PID),而在新創建的子進程中則返回0。若是fork 失敗則直接返回-1,失敗緣由存於errno中。指針

 

l  waitpid(等待子進程中斷或結束)blog

定義函數  pid_t waitpid(pid_t pid,int * status,int options);繼承

函數調用  waitpid(pid, NULL, 0);

函數說明  waitpid()會暫時中止目前進程的執行,直到有信號來到或子進程結束。若是在調用waitpid()時子進程已經結束,則wait()會當即返回子進程結束狀態值。子進程的結束狀態值會由參數status返回,而子進程的進程識別碼也會一快返回。若是不在乎結束狀態值,則參數status能夠設成NULL。參數pid爲欲等待的子進程識別碼,其餘數值意義以下:

pid<-1 等待進程組識別碼爲pid絕對值的任何子進程。

pid=-1 等待任何子進程,至關於wait()。

pid=0 等待進程組識別碼與目前進程相同的任何子進程。

pid>0 等待任何子進程識別碼爲pid的子進程。

返回值  若是執行成功則返回子進程識別碼(PID),若是有錯誤發生則返回-1。失敗緣由存於errno

 

l  getpid(取得進程識別碼) 

定義函數  pid_t getpid(void);

函數說明  getpid()用來取得目前進程的進程識別碼,許多程序利用取到的此值來創建臨時文件,以免臨時文件相同帶來的問題。

返回值    目前進程的進程識別碼

 

l  exit(正常結束進程) 

定義函數  void exit(int status);

函數說明  exit()用來正常終結目前進程的執行,並把參數status返回給父進程,而進程全部的緩衝區數據會自動寫回並關閉未關閉的文件。

 

l  execl(執行文件)

定義函數  int execl(const char * path,const char * arg,....);

函數說明  execl()用來執行參數path字符串所表明的文件路徑,接下來的參數表明執行該文件時傳遞過去的argv(0)、argv[1]……,最後一個參數必須用空指針(NULL)做結束。

返回值    若是執行成功則函數不會返回,執行失敗則直接返回-1,失敗緣由存於errno中。

調用ls命令範例: execl("/bin/ls", "/bin/ls",  "-l" , "/etc", NULL);

 

 安裝VMware Workstation Pro,下載Fedora Linux鏡像文件,安裝成功後以下圖。打開終端,輸入命令su進入管理員帳戶,輸入yum install gcc 安裝gcc編譯器,測試編譯環境正常

 

單個子進程的建立分析:經過gcc first.c進行編譯,在.a/.out執行輸出,例程剛開始輸出父進程pid 2218

#include<unistd.h>

#include<stdarg.h>

#include<time.h>

#include<sys/types.h>

#include<sys/wait.h>

#include<stdio.h>

#include<stdlib.h>

 

int tprintf (const char*fmt, ...);

int main(void)

{

       int i=0 ,j=0;

       pid_t pid;

       printf("Hello from Parent Process, PID is %d.\n", getpid());

 

 

 

  1. fork()會產生一個新的子進程,其子進程會複製父進程的數據與堆棧空間,並繼承父進程的用戶代碼,組代碼,環境變量、已打開的文件代碼、工做目錄和資源限制等。由於父與子進程的pid值不同,能夠分別對父進程和子進程作操做,當pid爲0時能夠對子進程作操做,當pid>0時對父進程作操做,當pid爲-1時建立進程失敗輸出提示信息;

       pid = fork();

       if(pid == 0) //child process

       {

              sleep(1);

              for(i=0;i<3;i++)

              {

                     printf("Hello from Child Process %d. %d times\n", getpid(), i+1);

                     sleep(1);

              }

       }

       else if(pid != -1) //parent process

       {

              tprintf("Parent forked one child process--%d.\n",pid);

              tprintf("Parent is waiting for child to exit.\n");

              waitpid(pid,NULL,0);

              tprintf("Child Process has exited.\n");

              tprintf("Parent had exited.\n");

       }

       else

       {

              tprintf("Everything was done without error.\n");

       }

       return 0;

}

 

waitpid()會暫時中止目前進程的執行,直到有信號來到或子進程結束。若是在調用waitpid()時子進程已經結束,則wait()會當即返回子進程結束狀態值。子進程的結束狀態值會由參數status返回,而子進程的進程識別碼也會一快返回。若是不在乎結束狀態值,則參數status能夠設成NULL。

int tprintf(const char*fmt, ...)

{

       va_list args;

       struct tm *tstruct;

       time_t tsec;

       tsec = time(NULL);

       tstruct = localtime(&tsec);

       printf("%02d:%02d:%02d %5d|", tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec, getpid());

       va_start(args,fmt);

       return vprintf(fmt,args);

}

 

當pid=-1時建立進程失敗輸出錯誤時間、PID等錯誤信息。最後運行結果以下:

 

 

在子進程中調用外部命令

#include<unistd.h>

#include<stdarg.h>

#include<time.h>

#include<sys/types.h>

#include<sys/wait.h>

#include<stdio.h>

#include<stdlib.h>

 

int tprintf (const char*fmt, ...);

 

int main(void)

{

       pid_t pid;

       pid = fork();

 

       if(pid == 0) //child process

       {

              sleep(5);

              tprintf("Hello from Child Process!\n");

              tprintf("I am calling exec.\n");

              execl("/bin/ps","-a",NULL);

              tprintf("You should never see this because the child is already gone.\n");

       }

 

int execl(const char * path,const char * arg,....)用來執行參數path字符串所表明的文件路徑,接下來的參數表明執行該文件時傳遞過去的argv(0)、argv[1]……,最後一個參數必須用空指針(NULL)做結束。返回值:若是執行成功則函數不會返回,執行失敗則直接返回-1,失敗緣由存於errno中;

 

       else if(pid != -1) //parent process

       {

              tprintf("Hello from Parent,pid %d.\n", getpid());

              sleep(1);

              tprintf("Parent forked process %d.\n",pid);

              sleep(1);

              tprintf("Parent is waiting for child to exit.\n");

              waitpid(pid,NULL,0);

              tprintf("Parent had exited.\n");

       }

 

sleep是讓線程指定休眠時間,而後繼續工做  wait則是等待,直到有線程通知notify()喚醒他纔會從新工做;

       else

       {

              tprintf("Everything was done without error.\n");

       }

       return 0;

}

 

int tprintf(const char*fmt, ...)

{

       va_list args;

       struct tm *tstruct;

       time_t tsec;

       tsec = time(NULL);

       tstruct = localtime(&tsec);

       printf("%02d:%02d:%02d %5d|", tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec, getpid());

       va_start(args,fmt);

       return vprintf(fmt,args);

}

 

 

編寫一段程序實現如下功能:

使用系統調用fork()建立兩個子進程

各個子進程顯示和輸出一些提示信息和本身的進程標識符。

父進程顯示本身的進程ID和一些提示信息,而後調用waitpid()等待多個子進程結束,並在子進程結束後顯示輸出提示信息表示程序結束。

 

#include<unistd.h>

#include <stdarg.h>

#include <time.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <stdio.h>

#include <stdlib.h>

 

int tprintf(const char*fmt,...);

 

int main()

{

       int i=0,j=0;

       pid_t pid1;

       pid_t pid2;

       printf("Hello from Parent Process,PID is %d.\n",getpid());

       pid1 = fork();

       if(pid1 == 0)

       {

              sleep(1);

              for(i=0;i<3;i++)

       {

          printf("Hello from Child Process one %d. %d times\n",getpid(),i+1);

          sleep(1);

       }

       }

       else if(pid1 !=-1)

       {

              tprintf("Part forked one child process--%d.\n",pid1);

              tprintf("Parent is waiting for child to exit.\n");

              waitpid(pid1,NULL,0);

              pid2 = fork();

              if(pid2 == 0)

              {

                     sleep(1);

                     for(i=0;i<3;i++)

                     {

                            printf("Hello from Child Process two %d. %d times\n",getpid(),i+1);

                            sleep(1);

                     }

              }

              else if(pid2 !=-1)

              {

                     tprintf("Part forked one child process--%d.\n",pid2);

                     tprintf("Parent is waiting for child to exit.\n");

                     waitpid(pid2,NULL,0);

                     tprintf("Child Process has exited.\n");

                     tprintf("Parent had exited.\n");

              }      

       }

       else  tprintf("Everything was done without error.\n");  

       return 0;

}

 

int tprintf(const char*fmt,...)

{

       va_list args;

       struct tm *tstruct;

       time_t tsec;

       tsec = time(NULL);

       tstruct = localtime (&tsec);

       printf("%02d:%02d:%02d:%5d",tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec,

       getpid());

       va_start(args,fmt);  

       return vprintf(fmt,args);

}

 

 

經過父進程建立一個子進程,運行一個子進程,再建立一個子進程,再運行一個子進程的方式,輸出各個進程的標識碼,能夠獲得正確的結果。而當兩個子進程同時fork()時,會產生3個子進程,這是應爲2個fork()放在一塊兒時,會多fork()一個子進程。

 

 

 建立多個(3個以上)進程併發運行,控制好各個子進程輸出本身的進程標識符和一些提示信息

 

#include<unistd.h>

#include<stdarg.h>

#include<time.h>

#include<sys/types.h>

#include<sys/wait.h>

#include<stdio.h>

#include<stdlib.h>

 

int tprintf (const char*fmt, ...);

 

int main(void)

{

       int i=0 ,j=0;

       pid_t pid,pid1,pid2;

       printf("Hello from Parent Process, PID is %d.\n", getpid());

 

       pid = fork();//fork1

 

       if(pid == 0) //child process 1

       {

 

              sleep(1);

              for(i=0;i<3;i++)

              {

                     printf("Hello from Child Process 11111 %d. %d times\n", getpid(), i+1);

                     sleep(5);

              }

       }

       else if(pid != -1) //parent process

       {

              tprintf("Parent forked 111 child process--%d.\n",pid);

 

                pid1 = fork();//fork2

 

                if(pid1 == 0) //child process 2

                 {

                     sleep(1);

                        for(i=0;i<3;i++)

                        {

                              printf("Hello from Child Process 22222 %d. %d times\n", getpid(), i+1);

                              sleep(5);

                        }

                 }

                 else if(pid1 != -1) //parent process

                 {

                     tprintf("Parent forked 222 child process--%d.\n",pid);

                                   

                     pid2 = fork();//fork3

 

                     if(pid2 == 0) //child process 3

                     {

                           sleep(1);

                           for(i=0;i<3;i++)

                           {

                                  printf("Hello from Child Process 33333 %d. %d times\n", getpid(), i+1);

                                  sleep(5);

                           }

                      }

                      else if(pid2 != -1) //parent process

                      {

                            tprintf("Parent forked 333 child process--%d.\n",pid);

 

                         //wait for children

                         pid_t temp_p;

                         while((temp_p = waitpid(-1, NULL, 0)) > 0)

                         {

                            tprintf("child had exited %d \n",temp_p);

                         }

                            tprintf("Parent had exited.\n");

                      }

                      else

                      {

                           tprintf("3333 Everything was done without error.\n");

                      }

                 }

                 else

                 {

                      tprintf("2222 Everything was done without error.\n");

                 }

       }

       else

       {

              tprintf("1111 Everything was done without error.\n");

       }

           

       return 0;

}

 

int tprintf(const char*fmt, ...)

{

       va_list args;

       struct tm *tstruct;

       time_t tsec;

       tsec = time(NULL);

       tstruct = localtime(&tsec);

       printf("%02d:%02d:%02d %5d|", tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec, getpid());

       va_start(args,fmt);

       return vprintf(fmt,args);

}

 

輸出結果與設想中的順序不一樣。由於佔用內存的進程不會由於wait pid中的PID參數而固定不變,而是三個子進程會按照第一次運行的順序繼續運行,也就是第一次運行的順序固定以後,後面的運行順序再也不改變。所以輸出順序結果以下圖:

 做者:Nathaneko

相關文章
相關標籤/搜索