1. 程式人生 > >exec函式族,vfork,程序退出,銷燬程序(殭屍程序 孤兒程序)

exec函式族,vfork,程序退出,銷燬程序(殭屍程序 孤兒程序)

參考文章

waitpid和wait

https://www.cnblogs.com/LUO77/p/5804436.html

https://www.cnblogs.com/13224ACMer/p/6390702.html

https://blog.csdn.net/zhangxiao93/article/details/72859312

vfork和fork

https://blog.csdn.net/ValDC_Morning/article/details/77414826

exec

https://blog.csdn.net/zjwson/article/details/53337212

exec

void PID::fun1()
{
    /*
     exec函式族
     在fork後的子程序中使用exec函式族,可以裝入和執行其它程式(子程序替換原有程序,和父程序做不同的事)。
     */
    cout<<"exec"<<endl;
    char *arg[]={"ls","-al",NULL};
    pid_t pid=fork();
    if(pid==0)//  子程序
    {
        cout<<" 子程序中:"<<endl;
        execv("/bin/ls", arg);

        exit(0);
    }
    else if(pid>0)//父程序
    {
        cout<<" 父程序中:execl沒有執行"<<endl;
        execl("/bin/date", "/bin/date");
        exit(1);
    }
    else
    {
        perror("建立程序失敗\n");
        exit(2);
    }
}

vfork

void PID::fun2()
{
    /*
     vfork()函式用來建立一個新程序,而這個新程序的目的是exec一個新程式。
     vfork建立的子程序與父程序共享地址空間,即子程序完全執行在父程序的地址空間上,子程序對虛擬地址空間的修改同樣為父程序所見.
     vfork保證子程序先執行,它呼叫exec或exit後父程序才能排程執行,fork的父子程序執行順序不定,取決於核心的排程演算法。
     */
    cout<<"vfork()"<<endl;
    int temp=0;
    cout<<"vfork建立程序前 temp:"<<temp<<endl;
    pid_t pid;
    pid=vfork();
    if(pid==0)
    {
        temp++;
        cout<<"子";
    }
    else if(pid>0)
    {
        cout<<"父";

    }
    cout<<"程序,程序標示符:"<<getpid()<<" temp:"<<temp<<endl;
    exit(0);
}

exit

void PID::fun3()
{
    /*
     exit  和 _exit 區別
     */
    cout<<"exit pid"<<endl;
    pid_t pid;
    pid=fork();
    if(pid==0)
    {
        cout<<"子程序"<<endl;
         cout<<"子:緩衝區資料還在";
        exit(0);
    }
    else if(pid>0)
    {
        cout<<"父程序"<<endl;
        cout<<"父:緩衝區資料還在";
        _exit(0);
    }

}

void PID::fun4()
{
    /*
     殭屍程序:子程序終止了,但是父程序沒有回收子程序的資源PCB。使其成為殭屍程序
     
     孤兒程序:父程序先與子程序結束了,使得子程序失去了父程序,這個時候子程序會被1號程序init程序領養,成為孤兒程序
     1)  wait()函式用於使父程序(也就是呼叫wait()的程序)阻塞,直到一個子程序結束或者該程序接收到了一個指定的訊號為止。如果該父程序沒有子程序或者它的子程序已經結束,則wait()函式就會立即返回。
     
     2) waitpid()的作用和wait()一樣,但它並不一定要等待第一個終止的子程序(它可以指定需要等待終止的子程序),它還有若干選項,如可提供一個非阻塞版本的 wait()功能,也能支援作業控制。實際上,wait()函式只是 waitpid()函式的一個特例,在Linux 內部實現 wait()函式時直接呼叫的就是waitpid()函式。
     
     */
    cout<<"wait &&waitpid"<<endl;
    pid_t pid;
    pid=fork();
    if(pid<0)
    {
        perror("fork error\n");
        exit(1);
    }
    else if(pid==0)
    {
        cout<<"child pid:"<<getpid()<<endl<<"child's dad:"<<getppid()<<endl;
        //sleep(3);
        //exit(0);
    }
    else 
    {
        pid_t pid2;
        //pid2=wait(NULL);//阻塞父程序 成功返回子程序pid
        pid2=waitpid(pid,NULL,0);
        cout<<"dad pid:"<<getpid()<<endl;
        cout<<"wait pid:"<<pid2<<endl;//返回 -1 估計是mac自己把子程序解決掉了
    }
    exit(0);
}
void PID::fun4_2()//waitpid和wait類似 多了一個指定等待的程序 最後引數是阻塞方式
{
    cout<<"wait &&waitpid"<<endl;
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork failed");
        exit(1);
    }
    
    if (pid == 0)
    {//in child
        int i;
        for (i = 3; i > 0; i--) {
            printf("This is the child %d\n",getpid());
            sleep(1);
        }
        exit(3);//返回3,執行時可以看到
        //子程序睡眠3秒之後就退出了
    }
    
    else
    {//in parent
        int stat_val;
        waitpid(pid, &stat_val, 0);//以阻塞方式等待回收子程序,第三個引數0,表示阻塞方式
        if (WIFEXITED(stat_val))//正常退出
            printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
        else if (WIFSIGNALED(stat_val))//檢視被什麼訊號關閉
            printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
    }
};

全部程式

類的宣告

//
//  PID.hpp
//  pid_charpter_7
//
//  Created by 藍貓 on 2018/11/3.
//  Copyright © 2018年 藍貓. All rights reserved.
//

#ifndef PID_hpp
#define PID_hpp

#include <stdio.h>
namespace SYA
{
    class PID
    {
    public:
        void fun1();//exec函式族
        void fun2();// vfork()
        void fun3();//exit  和 _exit
        void fun4();// 銷燬程序
        void fun4_2();
    };

};

#endif /* PID_hpp */

類的實現

//
//  PID.cpp
//  pid_charpter_7
//
//  Created by 藍貓 on 2018/11/3.
//  Copyright © 2018年 藍貓. All rights reserved.
//

#include "PID.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
using std::cout;
using std::endl;
using namespace SYA;
void PID::fun1()
{
    /*
     exec函式族
     在fork後的子程序中使用exec函式族,可以裝入和執行其它程式(子程序替換原有程序,和父程序做不同的事)。
     */
    cout<<"exec"<<endl;
    char *arg[]={"ls","-al",NULL};
    pid_t pid=fork();
    if(pid==0)//  子程序
    {
        cout<<" 子程序中:"<<endl;
        execv("/bin/ls", arg);

        exit(0);
    }
    else if(pid>0)//父程序
    {
        cout<<" 父程序中:execl沒有執行"<<endl;
        execl("/bin/date", "/bin/date");
        exit(1);
    }
    else
    {
        perror("建立程序失敗\n");
        exit(2);
    }
}
void PID::fun2()
{
    /*
     vfork()函式用來建立一個新程序,而這個新程序的目的是exec一個新程式。
     vfork建立的子程序與父程序共享地址空間,即子程序完全執行在父程序的地址空間上,子程序對虛擬地址空間的修改同樣為父程序所見.
     vfork保證子程序先執行,它呼叫exec或exit後父程序才能排程執行,fork的父子程序執行順序不定,取決於核心的排程演算法。
     */
    cout<<"vfork()"<<endl;
    int temp=0;
    cout<<"vfork建立程序前 temp:"<<temp<<endl;
    pid_t pid;
    pid=vfork();
    if(pid==0)
    {
        temp++;
        cout<<"子";
    }
    else if(pid>0)
    {
        cout<<"父";

    }
    cout<<"程序,程序標示符:"<<getpid()<<" temp:"<<temp<<endl;
    exit(0);
}
void PID::fun3()
{
    /*
     exit  和 _exit 區別
     */
    cout<<"exit pid"<<endl;
    pid_t pid;
    pid=fork();
    if(pid==0)
    {
        cout<<"子程序"<<endl;
         cout<<"子:緩衝區資料還在";
        exit(0);
    }
    else if(pid>0)
    {
        cout<<"父程序"<<endl;
        cout<<"父:緩衝區資料還在";
        _exit(0);
    }

}
void PID::fun4()
{
    /*
     殭屍程序:子程序終止了,但是父程序沒有回收子程序的資源PCB。使其成為殭屍程序
     
     孤兒程序:父程序先與子程序結束了,使得子程序失去了父程序,這個時候子程序會被1號程序init程序領養,成為孤兒程序
     1)  wait()函式用於使父程序(也就是呼叫wait()的程序)阻塞,直到一個子程序結束或者該程序接收到了一個指定的訊號為止。如果該父程序沒有子程序或者它的子程序已經結束,則wait()函式就會立即返回。
     
     2) waitpid()的作用和wait()一樣,但它並不一定要等待第一個終止的子程序(它可以指定需要等待終止的子程序),它還有若干選項,如可提供一個非阻塞版本的 wait()功能,也能支援作業控制。實際上,wait()函式只是 waitpid()函式的一個特例,在Linux 內部實現 wait()函式時直接呼叫的就是waitpid()函式。
     
     */
    cout<<"wait &&waitpid"<<endl;
    pid_t pid;
    pid=fork();
    if(pid<0)
    {
        perror("fork error\n");
        exit(1);
    }
    else if(pid==0)
    {
        cout<<"child pid:"<<getpid()<<endl<<"child's dad:"<<getppid()<<endl;
        //sleep(3);
        //exit(0);
    }
    else 
    {
        pid_t pid2;
        //pid2=wait(NULL);//阻塞父程序 成功返回子程序pid
        pid2=waitpid(pid,NULL,0);
        cout<<"dad pid:"<<getpid()<<endl;
        cout<<"wait pid:"<<pid2<<endl;//返回 -1 估計是mac自己把子程序解決掉了
    }
    exit(0);
}
void PID::fun4_2()//waitpid和wait類似 多了一個指定等待的程序 最後引數是阻塞方式
{
    cout<<"wait &&waitpid"<<endl;
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork failed");
        exit(1);
    }
    
    if (pid == 0)
    {//in child
        int i;
        for (i = 3; i > 0; i--) {
            printf("This is the child %d\n",getpid());
            sleep(1);
        }
        exit(3);//返回3,執行時可以看到
        //子程序睡眠3秒之後就退出了
    }
    
    else
    {//in parent
        int stat_val;
        waitpid(pid, &stat_val, 0);//以阻塞方式等待回收子程序,第三個引數0,表示阻塞方式
        if (WIFEXITED(stat_val))//正常退出
            printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
        else if (WIFSIGNALED(stat_val))//檢視被什麼訊號關閉
            printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
    }
};

main

//
//  main.cpp
//  pid_charpter_7
//
//  Created by 藍貓 on 2018/11/2.
//  Copyright © 2018年 藍貓. All rights reserved.
//

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <memory>
#include "PID.hpp"
using namespace std;
using SYA::PID;
int main(int argc, const char * argv[])
{
    
    shared_ptr<SYA::PID> obj=make_shared<SYA::PID>();
    //PID *obj;
    //obj->fun1();
    //obj->fun2();
    //obj->fun3();
    //obj->fun4();
    obj->fun4_2();
    return 0;
}