系統(tǒng)編程-文件操作4

exec(鳩占鵲巢)

  • 查找文件:fins /usr

execl

#include <unistd.h> //read() write()
#include <stdio.h>
#include <string.h>
#include <errno.h>//errno 
/*open()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>

/* dir open */
#include <sys/types.h>
#include <dirent.h>
int main()
{
    int ret=-1;
    //使用新進程鏡像替換當前進程鏡像
    //但是當前進程的ID被新進程使用
    //-->鳩占鵲巢
    //想看user/include下面的內(nèi)容(路徑+要執(zhí)行的命令+命令的方式)
    //第一個參數(shù):可執(zhí)行文件的路徑,之后的參數(shù),可執(zhí)行文件執(zhí)行的方式
    //ret=execl("/bin/ls","ls","/usr/include","-l",NULL);
    //ret=execl("./exec1","exec1",NULL);
    //ret=execl("/usr/bin/gedit","gedit","dirCopy.c",NULL);
    //ret=execlp("gedit","gedit","dirCopy.c",NULL);//可以打開dirCopy.c文件
    /*ret=execlp("exec1","exec1",NULL);//運行不起來,不會循環(huán)打印hello world,因為不加路徑,則會去系統(tǒng)找相應的命令,但是找不到,可以不指定需要執(zhí)行文件的命令,啟動該執(zhí)行文件時,到系統(tǒng)默認路徑下找該執(zhí)行文件,若找到了則執(zhí)行,否則出錯返回
    
    if(-1==ret)
    {
        perror("execlp");
        return -1;
    }*/
        /*char *const argv[]={"ls","/usr/include","-l",NULL};
    ret=execv("/bin/ls",argv);*///運用數(shù)組將后面的放進數(shù)組里。
    char *const argv[]={"gedit","dirCopy.c",NULL};
    ret=execvp("gedit",argv);
    return 0;
}

  • 模擬一個終端,可以同時打開兩個文件
#include <unistd.h> //read() write()
#include <string.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父進程
    {
        while(1)
        {
            printf("this is parent\n");
            sleep(1);
        }
    }
    else if(0==pid)
    {
        //./a.out /bin/ls /usr/include -l
        int ret=-1;
        ret=execv(argv[1],argv+1);//argv+2:表示從第2個往后,直到碰到NULL
        if(-1==ret)
        {
            perror("execv");
            return -1;
        }
    }
    /*else if(-1==pid)
    {
        perror()
    }*/
    return 0;
}
//以下為運行結(jié)果

Paste_Image.png
Paste_Image.png

Paste_Image.png

模擬一個終端


#include <unistd.h> //read() write()
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *getInput(char *argv[])
{
    int ret=-1;
    int i=0;
    char *pData=NULL;
    pData=(char *)malloc(64);
    while(EOF!=scanf("%s",pData))
    {
        printf("%s\n",pData);
        argv[i]=pData;
        i++;
        pData=(char *)malloc(64);
    }
    free(pData);
    argv[i]=NULL;
    return NULL;
}
void showArgv(char *argv[])
{
    int i=0;
    while(argv[i]!=NULL)
    {
        printf("%s\n",argv[i]);
        i++;
    }
}
int main(int argc,char *argvm[])
{
    char *argv[32]={NULL};
    while(1)
    {
        printf("MyTermal@sq$:");
        getInput(argv);

        pid_t pid=-1;
        pid=fork();
        if(0==pid)
        {
            int ret=-1;
            ret=execvp(argv[0],argv);
            if(ret==-1)
            {
                perror("execvp");
                return -1;
            }
        }
    }
    return 0;
}

Paste_Image.png

Paste_Image.png
  • 上一個程序沒有處理僵尸進程,所以不完善

atexit(在程序正常結(jié)束的時候,調(diào)用)

  • 用戶層,對相關(guān)的進行清理
  • 到內(nèi)核層,也對相關(guān)的進行清理

//錯誤號被設置:出錯可以看到錯誤信息,否則看不到

#include<stdio.h>
#include<stdlib.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//進程正常結(jié)束時首先在用戶層做一些善后工作
//然后進入內(nèi)核層做一些善后工作
int main(void)
{
    //atexit注冊的函數(shù)會在進程正常結(jié)束后被執(zhí)行
    //執(zhí)行的順序和注冊的順序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    

    printf("hello world\n");
    return 0;
}

Paste_Image.png
  • 加了exit(-1),就自殺了
#include<stdio.h>
#include<stdlib.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//進程正常結(jié)束時首先在用戶層做一些善后工作
//然后進入內(nèi)核層做一些善后工作
int main(void)
{
    //atexit注冊的函數(shù)會在進程正常結(jié)束后被執(zhí)行
    //執(zhí)行的順序和注冊的順序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    
    exit(-1);//自殺
    printf("hello world\n");
    return 0;
}

//不會執(zhí)行hello world

Paste_Image.png

abort(非正常結(jié)束)

#include<stdio.h>
#include<stdlib.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//進程正常結(jié)束時首先在用戶層做一些善后工作
//然后進入內(nèi)核層做一些善后工作
int main(void)
{
    //atexit注冊的函數(shù)會在進程正常結(jié)束后被執(zhí)行
    //執(zhí)行的順序和注冊的順序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    abort();//已放棄(核心已轉(zhuǎn)儲)
//  exit(-1);//自殺
    printf("hello world\n");
    return 0;
}
//用了abort,就段錯誤

  • 可以退出整個程序的
  1. return 0;exit():會首先在用戶層做一些善后工作,然后進入內(nèi)核層組一些善后工作
  1. _exit():直接進入內(nèi)核層作一些善后工作
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
void fun1()
{
    printf("fun1...\n");
}
void fun2()
{
    printf("fun2...\n");
}
void fun3()
{
    printf("fun3...\n");
}
//進程正常結(jié)束時首先在用戶層做一些善后工作
//然后進入內(nèi)核層做一些善后工作
int main(void)
{
    //atexit注冊的函數(shù)會在進程正常結(jié)束后被執(zhí)行
    //執(zhí)行的順序和注冊的順序相反
    atexit(fun1);
    atexit(fun2);
    atexit(fun3);
    _exit(-1);//也能退出程序(進程結(jié)束)
//  abort();//已放棄(核心已轉(zhuǎn)儲)
//  exit(-1);//自殺
    printf("hello world\n");
    return 0;
}

//用了_exit(-1):不會進行運行直接退出

作業(yè)

  1. 完善文件拷貝(假如將一個目錄拷貝到了文件里,進行分析)
  2. 進程的狀態(tài)以及狀態(tài)間的轉(zhuǎn)化
  3. 獨立完成模仿終端代碼

進程與通信

  • IPC:代表進程間

進程間的通信方式

  1. 管道通信:命名管道和無名管道
  • env | grep unix :grep是匹配規(guī)則,只要數(shù)據(jù)符合規(guī)則,則全部都提取出來
Paste_Image.png

pipe(管道通信)

  • 父進程發(fā)送消息,子進程接收消息
  • 如果要換成子進程發(fā)消息,父進程接收
#include<unistd.h> //pipe() fork()
#include<stdio.h>
#include<string.h>
int main()
{
    int pipefd[2]={-1};//管道兩端,一端讀,一端寫
    int ret=-1;
    //創(chuàng)建一個管道(不屬于父進程)
    ret=pipe(pipefd);
    if(-1==ret)
    {
        perror("pipe");//創(chuàng)建失敗
        return -1;
    }
    //創(chuàng)建一個子進程
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父進程
    {
        close(pipefd[0]);//一個說
        while(1)
        {
            write(pipefd[1],"Hello child",11);
            sleep(1);
        }
    }
    else if(pid==0)//子進程
    {   
        close(pipefd[1]);//一個聽,不能同時說,同時聽
        char caBuf[32]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));//清空讀掉的空間
            read(pipefd[0],caBuf,11);
            printf("%s\n",caBuf);
            sleep(1);
        }
    }
    else if(pid==-1)//創(chuàng)建進程失敗
    {
        perror("fork");
        return -1;
    }
    return 0;
}

  • 父進程與子進程之間進行相互通信
#include<unistd.h> //pipe() fork()
#include<stdio.h>
#include<string.h>
//通過pipe()函數(shù)創(chuàng)建的管道屬于無名管道,只能在父子進程間使用,或者子進程間使用,創(chuàng)建該管道的進程一旦結(jié)束,則該無名管道將會被銷毀
int main()
{
    int pipefd[2]={-1};//管道兩端,一端讀,一端寫
    int ret=-1;
    //創(chuàng)建一個管道(不屬于父進程),管道兩邊的描述符存儲到pipefd數(shù)組中
    //pipefd[0]表示數(shù)據(jù)流出端,可以從此端讀取數(shù)據(jù)
    //pipefd[1]表示數(shù)據(jù)進入端,可以往此端寫入數(shù)據(jù)
    ret=pipe(pipefd);
    if(-1==ret)
    {
        perror("pipe");//創(chuàng)建失敗
        return -1;
    }
    //創(chuàng)建一個子進程
    pid_t pid=-1;
    //管道的創(chuàng)建的是在內(nèi)核中,不獨立屬于進程
    //所以,fork產(chǎn)生子進程是并不會再次創(chuàng)建一個管道
    //只是對管道文件描述符進行了一次拷貝
    pid=fork();
    if(pid>0)//父進程
    {
        int iSign=0;
        char caBuf[64]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));
            if(0==iSign)
            {
                printf("parent-input data:");
                scanf("%s",caBuf);
                write(pipefd[1],caBuf,strlen(caBuf));
                iSign=1;
            }
            else if(1==iSign)
            {
                read(pipefd[0],caBuf,sizeof(caBuf));
                printf("child says:%s\n",caBuf);
                iSign=0;
            }
            sleep(1);
        }
    }
    else if(pid==0)//子進程
    {   
        int iSign=1;
        char caBuf[64]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));
            if(0==iSign)
            {
                read(pipefd[0],caBuf,sizeof(caBuf));
                printf("parent says:%s\n", caBuf);
                iSign=1;
            }
            else if(1==iSign)
            {
                printf("child-input data:");
                scanf("%s",caBuf);
                write(pipefd[1],caBuf,strlen(caBuf));
                iSign=0;
            }
            sleep(1);
        }
    }
    else if(pid==-1)//創(chuàng)建進程失敗
    {
        perror("fork");
        return -1;
    }   return 0;
}

Paste_Image.png

進程在運行中不斷改變其運行狀態(tài),而運行的進程有三個基本狀態(tài)。

  1. 就緒狀態(tài):當進程已分配到除CPU以外所有必要的資源,只要獲得處理器便可立即執(zhí)行。
  2. 執(zhí)行狀態(tài):當進程已獲得處理器,其程序正在處理器上執(zhí)行。
  3. 阻塞狀態(tài):正在執(zhí)行的進程,由于等待某個事件發(fā)生而無法執(zhí)行時,便放棄處理機而處于阻塞狀態(tài),而引起進程阻塞的事件可能有很多種,如等待I/O完成,申請緩沖區(qū)不能滿足、等待信號等。
    而一個進程在運行期間,會不斷地從一個狀態(tài)轉(zhuǎn)換到另一個狀態(tài)。于是便有了進程的三種基本狀態(tài)間的相互轉(zhuǎn)換,如下示意圖:
Paste_Image.png
  1. 就緒->執(zhí)行:處于就緒狀態(tài)的進程,當進程調(diào)度程序為之分配了處理器后,該進程便由就緒狀態(tài)轉(zhuǎn)變?yōu)閳?zhí)行狀態(tài)。
  2. 執(zhí)行->就緒:處于執(zhí)行狀態(tài)的進程在其執(zhí)行進程中,因分配給它的一個時間片已用完而不得不讓處理器,于是進程從執(zhí)行狀態(tài)轉(zhuǎn)換成就緒狀態(tài)。
  3. 執(zhí)行->阻塞:正在執(zhí)行的進程因等待某種事件發(fā)生而無法繼續(xù)執(zhí)行時,便從執(zhí)行狀態(tài)變成阻塞狀態(tài)。
  4. 阻塞->就緒:處于阻塞狀態(tài)的進程,若其等待的事件已經(jīng)發(fā)生,于是進程由阻塞狀態(tài)轉(zhuǎn)變?yōu)榫途w狀態(tài)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容