多进程,fork(),exec()

fork系统调用用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进程称为父进程。创建新的子进程后,两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc(程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。
它不需要参数并返回一个整数值。下面是fork()返回的不同值。
负值:创建子进程失败。
零:返回到新创建的子进程。
正值:返回父进程或调用者。该值包含新创建的子进程的进程ID [1] 。
头文件

#include<unistd.h>/#包含<unistd.h>
#include<sys/types.h>/
#包含<sys/types.h>

pid_t fork( void);
(pid_t 是一个宏定义,其实质是int 被定义在#includesys/types.h>中)
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1

说明:原进程调用fork()函数创建子进程, fork()被调用一次返回两次,原进程中返回子进程id,新进程中返回值为0;
子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。
fork()例:

#include "head.h"

int main() {
    pid_t pid;
    if((pid = fork()) < 0) {
        perror("fork()"); //调用一次,返回两次,原进程返回新进程id(不为零),新进程返回

     exit(1);
    }
    if(pid) {
        printf("I'm parent process! <%d>--><%d>--><%d>\n",getppid(), getpid(), pid);
    }
    else {
        printf("Im child process!  <%d>--><%d>\n", getppid(), getpid());
    }
    return 0;
}
I'm parent process! <14180>--><14371>--><14372>
Im child process!  <14371>--><14372>

getpid---- 获取父进程id;
getppid---获取当前进程id;

例二:

#include "head.h"

int main() {
    pid_t pid;
    int i = 1;
    for(; i <=10; i++) {
        if ((pid = fork()) < 0) {
            perror("fork()");
            exit(1);
        }
        if (pid == 0) { //终止子进程,否则将继续调用fork(),会创建无数个子孙进程;
            break;
        }
    }
        if(!pid) {
            printf("I'm %dth child process!\n", i);
        }
        else
        printf("I'm the parent process!\n");
    return 0;
}


僵尸进程:子进程再其父进程未调用wait(),或 waitip()的情况下退出,这些进程将成为僵尸进程;如果父进程存在,且不调用wait(),这些进程将无法回收,等到父进程结束后由initi(1号进程)回收;
孤儿进程:父进程结束后他的其他子进程还存在,这些进程就是孤儿进程;这些进程将被init(1号进程)收养;

exec 函数
exec函数的原型如下:
int execl(const char * path,const char * arg,…);
int execle(const char * path,const char * arg,char * const envp[]);
int execlp(const char * file,const char * arg,…);
int execv(const char * path,char * const argv[]);
int execve(const char * path,char * const argv[],char * const envp[]);
int execvp(const char * file,char * const argv[]);
path:要执行的程序路径。可以是绝对路径或者是相对路径。在execv、execve、execl和execle这4个函数中,使用带路径名的文件名作为参数。
file:要执行的程序名称。如果该参数中包含“/”字符,则视为路径名直接执行;否则视为单独的文件名,系统将根据PATH环境变量指定的路径顺序搜索指定的文件。
argv:命令行参数的矢量数组。
envp:带有该参数的exec函数可以在调用时指定一个环境变量数组。其他不带该参数的exec函数则使用调用进程的环境变量。
arg:程序的第0个参数,即程序名自身。相当于argv[0]
…:命令行参数列表。调用相应程序时有多少命令行参数,就需要有多少个输入参数项。注意:在使用此类函数时,在所有命令行参数的最后应该增加一个空的参数项(NULL),表明命令行参数结束。
返回值:一1表明调用exec失败
,无返回表明调用成功。

使用exec函数族主要有两种情况:
(1)当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。
(2)如果一个进程想执行另一个程序,**那么它就可以调用fork函数新建一个进程,然后调用exec函数族中的任意一个函数,**这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。

#include "head.h"

int main() {
    pid_t pid;
    if((pid = fork()) < 0) {
        perror("fork()");
        exit(1);
    }
    if (pid) {
        wait(NULL);
    }
    else {
        //execl("/bin/cat", "cat", "/etc/hosts", NULL);
        execlp("cat", "cat", "/etc/hosts", NULL);
        printf("haha\n");
        fflush(stdout);
        // 这句不会输出,上一句执行成功后即被替换为cat 语句,17行之后将不再执行;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值