正在加载……
专注、离线、切勿分心

Linux下有四类创建子进程的函数:system() , fork() , exec*() , popen()

system函数

原型:
        #include <stdlib.h>
        int system(const char *string);

system函数通过调用 shell 程序 /bin/sh –c 来执行string所指定的命令,该函数在内部是通过调用execve(“/bin/sh”,..)函数来实现的通过system创建子进程后,原进程和子进程各自运行,相互间关联较少。如果system调用成功,将返回0
#include <stdio.h>
#include <stdlib.h>
int main()
{
        system("ls -l");       //system(“clear”);  表示清屏
        return 0;
}




fork函数

原型:
       #include <unistd.h>
       pid_t fork(void);  //父进程的返回值是子进程的进程号,子进程的返回值为0。若出错则返回-1

      在linuxfork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。它和其他函数的区别在于:它执行一次返回两个值。其中父进程的返回值是子进程的进程号,而子进程的返回值为0。若出错则返回-1。因此可以通过返回值来判断是父进程还是子进程。

       fork函数创建子进程的过程为:使用fork函数得到的子进程是父进程的一个复制品,它从父进程继承了进程的地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端,而子进程所独有的只有它的进程号、资源使用和计时器等。通过这种复制方式创建出子进程后,原有进程和子进程都从函数fork返回,各自继续往下运行,但是原进程的fork返回值与子进程的fork返回值不同,在原进程中,fork返回子进程的pid,而在子进程中,fork返回0, 如果fork返回负值,表示创建子进程失败

fork.c
     #include<stdio.h>
     #include<unistd.h>
     int main()
     {
           pid_t pid;
           pid=fork();
           if(pid==0)
           {
                 printf("I am child,my pid=%d,my ppid=%d\n",getpid(),getppid());
                 while(1);
         }
         else
         {
                 printf("child pid=%d\n",pid);
                 while(1);
         }
         return 0;
      }
先返回子进程的进程号给父进程;所以先执行的else,后面接着子进程返回0,执行if语句;
//不加while(1),父进程先执行,然后返回0结束,最后才执行子进程




//不加while(1)




#include <stdlib.h>
void exit(int status);   //退出进程
fork_stack.c
#include<stdio.h>
#include<unistd.h>
int main()
{
        pid_t pid;
        int i=3;
        pid=fork();
        if(pid==0)
        {
                i++;
                printf("I am child,my pid=%d,my ppid=%d\n",getpid(),getppid());
                while(1);
        }
        else
        {
                sleep(3);
                printf("i=%d\n",i);
                printf("child pid=%d\n",pid);
                while(1);
        }
        return 0;
}
程序先进入到else,然后睡眠3s,这个时间子进程开始执行,i++,由于栈分开,不影响父进程的栈,所以最后打印的i还是3



ps -elf | grep a   // 查看a开头的进程




fork_exit.c
#include<stdio.h>
#include<unistd.h>
#incldue<stdlib.h>
int main()
{
        pid_t pid;
        int i=3;
        pid=fork();
        if(pid==0)
        {
                i++;
                printf("I am child,my pid=%d,my ppid=%d\n",getpid(),getppid());
                exit(0);
        }
        else
        {
                printf("i=%d\n",i);
                printf("child pid=%d\n",pid);
                exit(0);
        }
        return 0;
}

//因为父进程先进入到else,exit后导致fork的子进程无法退出,卡住;查看进程,这个进程已经退出了




exec函数族

exec*由一组函数组成
            int execl(const char *path, const char *arg, ...);   //失败返回-1
            int execv(const char *path, char *const argv[]);     //失败返回-1
exec函数族的工作过程与fork完全不同fork是在复制一份原进程,而exec函数是用exec的第一个参数指定的程序覆盖现有进程空间(也就是说执行exec族函数之后,它后面的所有代码不在执行)。

path 是包括执行文件名的全路径名(二进制文件)

arg 是可执行文件的命令行参数,多个要分割;注意最后一个参数必须为NULL表示结束

参数:二进制文件全路径,二进制文件名,传递的参数,NULL(结束标志)

add.c execl.c 改写
#include<stdio.h>

int main(int argc,char* argv[])
{
        int i=atoi(argv[1]);
        int j=atoi(argv[2]);
        printf("sum=%d\n",i+j);
        return 0;
}
#include<unistd.h>
#include<stdio.h>

int main()
{
        execl("./add","./add","1","2",NULL);
        printf("I can not be here\n");
        return -1;
}
#include<unistd.h>
#include<stdio.h>

int main()
{
        char* argv[]={"add","1","2",NULL}
        execv("./add",argv);
        printf("I can not be here\n");
        return -1;
}



 popen()   //创建标准流管道

2016/5/18 9:38:56讲




posted on 2018-02-26 08:46  正在加载……  阅读(231)  评论(0编辑  收藏  举报