寒假學習 第15天 (linux 進階編程) 筆記 總結

來源:互聯網
上載者:User

寒假學習 第15天 (linux 進階編程)  筆記 總結


接著昨天

一、進程2.建立進程

   (1) int system(const char *command);

   (2) FILE *popen(const char *command, const char *type);

   (3) exec系列函數

       int execl( const char *path, const char *arg, ...);

       //第一個參數:替換的進程,第二個參數..... 命令列

       //命令列格式:命令名   選項參數     並且命令列必須、以0結尾
       int execlp( const char *file, const char *arg, ...);
       int execle( const char *path, const char *arg , ..., char * const envp[]);
       int execv( const char *path, char *const argv[]);
       int execvp( const char *file, char *const argv[]);

       替換當前進程的代碼空間的代碼資料,函數本生不會建立進程 見例子1

  execl與execlp的區別

     execl必須是絕對路徑,execlp不用 見例子2


例子1:

test.c

#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    printf("%d\n",getpid());    sleep(5);    return 0;}

#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    printf("%d\n",getpid());    int r=execl("test","mytest",NULL);//結尾必須是0    printf("end %d\n",r);    return 0;}

運行時 printf(“end %d\n”,r); 不會執行

並且列印的兩個pid相同


例子2:

#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    printf("%d\n",getpid());    int r=execl("/bin/ls","ls","-l",NULL);    printf("end %d\n",r);    return 0;}


(4) pid_t fork(void);

  1. 複製父進程的代碼跟執行位置,重fork開始就分兩個進程進行,例子1

  2. fork建立的進程,父子進程是同時進行的

      子進程建立好了以後,父進程馬上把時間片交給系統,然後系統在調度下一個時間片由那個執行。 例子2


例子1:

#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    printf("before creat process!\n");    int pid=fork();    printf("after creat process:%d\n",pid);    return 0;}結果:before creat process!after creat process:2651after creat process:0     //為什麼為0?因為fork不光複製父進程的代碼,還複製了父進程的執行位置,所以子進程中pid=fork() 是沒有執行的,pid為0.

例子2:

#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    printf("before creat process!\n");    int pid=fork();    while(1)    {        if(pid==0){            printf("AAAAA\n");            sleep(1);        }else{            printf("BBBBB\n");            sleep(1);        }    }    return 0;}結果:AAAAA 跟BBBBB交叉出現

3.進程的應用

  1. fork 的用處? 使用fork實現多任務(Unix本身是不支援多線程,有時就要用fork建立多進程)

  2. 實現多任務的方式

          1.線程

          2.進程

          3.訊號

          4.非同步

          5.進程池與線程池

例子:使用進程建立多任務(讓螢幕同時顯示時間跟隨機數)
#include <curses.h>#include <unistd.h>#include <stdlib.h>#include <time.h>WINDOW *wtime,*wnumb;int main(int argc, const char *argv[]){    initscr();    box(stdscr,0,0);    wtime=derwin(stdscr,3,10,0,(COLS-10));   //右上方顯示時間    wnumb=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2); //中間顯示隨機數    box(wtime,0,0);    box(wnumb,0,0);    refresh();    wrefresh(wtime);    wrefresh(wnumb);    if(fork()){     //父進程        time_t tt;        struct tm *t;        while(1)        {            tt=time(0);            t=localtime(&tt);            mvwprintw(wtime,1,1,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);            refresh();            wrefresh(wtime);            wrefresh(wnumb);            sleep(1);        }    }else{   //子進程        while(1){            mvwprintw(wnumb,1,1,"%8d",rand()%100000000);            refresh();            wrefresh(wtime);            wrefresh(wnumb);            usleep(100000);        }    }    endwin();    return 0;}

4.理解進程(1).父子進程的關係

       是獨立的兩個進程,有各自的pid

       從進程樹可以看出兩個獨立但不平行是父子節點關係(pstree可以查看進程樹)

(2)  父進程先結束

       子進程就依託根進程init (孤兒進程)

       理論上孤兒進程對系統沒有任何的危害。

    子進程先結束

        子進程會成為殭屍進程。

        殭屍進程不佔用記憶體,CPU但在我們的進程任務管理樹上佔用一個節點。

        殭屍進程會造成進程名額資源的浪費,所以要處理殭屍進程

 (3). 殭屍進程的回收(使用wait回收)

例子:

#include <stdio.h>#include <stdlib.h>#include <sys/wait.h>int main(int argc, const char *argv[]){    if(fork()){        int status;            printf("parent\n");        wait(&status);        printf("%d\n",WEXITSTATUS(status));        sleep(1000);    }else{        printf("child\n");        sleep(10);        exit(34);    }    return 0;}
運行10秒後 子進程回收,不會變成殭屍進程,pstree查看看不到子進程



4. 父進程怎麼知道子進程退出

     子進程結束通常會向父進程發送   一個SIGCHLD訊號(kill -l 可以查看所有訊號)

5.父進程處理子進程退出訊號

      signal(int sig,void(*fun)(int));

      向系統註冊:告訴系統只要sig訊號發生,系統就停止進程,並調用fun函數。

      當函數執行完畢,繼續原來的進程         (中斷)

          1 實現處理函數

          2使用signal來綁定訊號與函數

例子:殭屍進程回收

#include <stdio.h>#include <stdlib.h>#include <sys/wait.h>void deal(int s){    int status;    wait(&status);    printf("回收中!...\n");  //這個函數不執行完畢程式就不會進行下去    sleep(10);                       printf("回收完畢:%d\n",WEXITSTATUS(status));}int main(int argc, const char *argv[]){    if(fork()){        signal(17,deal); //向系統註冊  SIGCHLD 就是 17        while(1)        {            printf("parent\n");            sleep(1);        }    }else{        printf("child\n");        sleep(10);        printf("child out\n");        exit(34);    }    return 0;}


6. 父子進程的資源訪問   (1).記憶體資源1
#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    int a = 20;    if(fork()){        printf("patent a:%d\n",a);        printf("patent a:%p\n",&a);        a=33;        sleep(3);    }else{        printf("child a:%d\n",a);        printf("child a:%p\n",&a);        sleep(2);        printf("child a:%d\n",a);        printf("child a:%p\n",&a);    }    return 0;}結果:patent a:20patent a:0x7fffbd3e533cchild a:20child a:0x7fffbd3e533cchild a:20child a:0x7fffbd3e533c



#include <stdio.h>#include <unistd.h>int main(int argc, const char *argv[]){    int *a = (int *)malloc(4);    *a = 20;    if(fork()){        printf("patent a:%d\n",*a);        printf("patent a:%p\n",a);        a=33;        sleep(3);    }else{        printf("child a:%d\n",*a);        printf("child a:%p\n",a);        sleep(2);        printf("child a:%d\n",*a);        printf("child a:%p\n",a);    }    return 0;}結果:patent a:20patent a:0x1d2f010child a:20child a:0x1d2f010child a:20child a:0x1d2f010

由上面兩例子可得到 子進程複製了整個記憶體地區,但記憶體地區指向不同的物理空間(虛擬位址相同,但映射不同) 儘管複製,但記憶體獨立,不能互相訪問。
多進程實現多任務,進程之間的資料交換是個大問題Inter-Process Commucation 

2
#include <stdio.h>#include <unistd.h>#include <sys/mman.h>int main(int argc, const char *argv[]){    int *a = (int *)mmap(0,4,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,0,0);    *a = 20;    if(fork()){        printf("patent a:%d\n",*a);        printf("patent a:%p\n",a);        *a = 33;        sleep(3);    }else{        printf("child a:%d\n",*a);        printf("child a:%p\n",a);        sleep(2);        printf("child a:%d\n",*a);        printf("child a:%p\n",a);    }    return 0;}結果:patent a:20patent a:0x7f76f73f1000child a:20child a:0x7f76f73f1000child a:33              //改變了,child a:0x7f76f73f1000

#include <stdio.h>#include <unistd.h>#include <sys/mman.h>int main(int argc, const char *argv[]){  //跟上面的例子的區別只是把PROT_SHARE 改成MAP_PRIVATE    int *a = (int *)mmap(0,4,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,0,0);    *a = 20;    if(fork()){        printf("patent a:%d\n",*a);        printf("patent a:%p\n",a);        *a = 33;        sleep(3);    }else{        printf("child a:%d\n",*a);        printf("child a:%p\n",a);        sleep(2);        printf("child a:%d\n",*a);        printf("child a:%p\n",a);    }    return 0;}結果:patent a:20patent a:0x7fe9bb8ab000child a:20child a:0x7fe9bb8ab000child a:20   //沒有改變child a:0x7fe9bb8ab000
映射記憶體         MAP_SHARED: 映射到同一實體記憶體         MAP_PRIVATE: 映射到不同的實體記憶體


#include <stdio.h>#include <unistd.h>#include <sys/mman.h>int main(int argc, const char *argv[]){    int *a=sbrk(4);    *a = 20;    if(fork()){        printf("patent a:%d\n",*a);        printf("patent a:%p\n",a);        *a = 33;        sleep(3);    }else{        printf("child a:%d\n",*a);        printf("child a:%p\n",a);        sleep(2);        printf("child a:%d\n",*a);        printf("child a:%p\n",a);    }    return 0;}結果:patent a:20patent a:0x12a1000child a:20child a:0x12a1000child a:20child a:0x12a1000

sbrk映射的是 MAP_PRIVATE的
   (2).檔案資源
#include <stdio.h>#include <fcntl.h>int main(int argc, const char *argv[]){    int fd=open("test.txt",O_RDWR);    if(fork()){        printf("patent\n");        char buf[1024]={0};        read(fd,buf,1024);        printf("%s\n",buf);    }else{        printf("child\n");        char buf[1024]={0};        read(fd,buf,1024);        printf("%s\n",buf);    }    close(fd);    return 0;}test.txt 內容123456結果:patent123456child

檔案是獨立的,close() ,每個進程都要有
為什麼子進程沒有內容?因為read中系統管理的指標移動了,兩個進程操作的是同一個核心對象
改成下面這樣就沒問題了
#include <stdio.h>#include <fcntl.h>int main(int argc, const char *argv[]){    int fd=open("test.txt",O_RDWR);    if(fork()){        printf("patent\n");        char buf[1024]={0};        lseek(fd,0,SEEK_SET);        read(fd,buf,1024);        printf("%s\n",buf);    }else{        printf("child\n");        char buf[1024]={0};        lseek(fd,0,SEEK_SET);        read(fd,buf,1024);        printf("%s\n",buf);    }    close(fd);    return 0;}結果:patent123456child123456


#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/mman.h>main(){    int fd=open("test.txt",O_RDWR|O_CREAT|O_TRUNC,0666);    if(fork())    {        write(fd,"Hello",5);        close(fd);    }else{        write(fd,"Word",5);        close(fd);    }}cat test.txt結果:HelloWord




#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/mman.h>main(){    if(fork())    {        int fd=open("test.txt",O_RDWR);        write(fd,"Hello",5);        close(fd);    }else{        int fd=open("test.txt",O_RDWR);        write(fd,"Word",5);        close(fd);    }}cat test.txt 結果:Word


結論:   兩個進程之間,檔案描述付指向的是同一個檔案對象    進程的資料交換,居於兩種方式:             記憶體:有序/無序    mmap             檔案:有序/無序    普通檔案     由此可得出所有進程對象的通訊都是基於核心對象的:檔案,記憶體,隊列



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.