zoukankan      html  css  js  c++  java
  • Linux 进程创建一(system和fork)

    一:system系统调用
    #include <stdlib.h>
    int system(const char *string);
    system函数传递给/bin/sh -c 来执行string所指定的命令。
    string中可以包含选项和参数
    如果没有找到/bin/sh。函数返回127,如果出现其他错误返回-1,成功返回0,但如果string为NULL,返回一个非0值
    system调用其他进程是通过shell调用其他进程,本程序进程与被调用的进程之间没有关系。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    int main(int arg, char * args[])
    {
        system("ls -l");
        return 0;
    }
    二:fork系统调用
    #include<unistd.h>
    pid_t fork(void);
    fork执行成功,向父进程返回子进程的PID,并向子进程返回0,这意味着fork即使只调用一次,也会返回两次。
    fork创建的新进程是和父进程(除了PID和PPID)一样的副本。
    父进程和子进程之间有点区别,子进程没有继承父进程的超时设置(使用alarm调用)、父进程创建的文件锁,或者未决信号。
    但是子进程会继承父进程的文件描述符,内存空间大小,代码
    你不能预计父进程是在他的子进程之前还是之后运行,他的执行是无序的,是异步的。
    fork的异步行为意味着你不应该在子进程中执行依赖与父进程的代码,反之亦然。
    fork调用可能失败,原因是系统上已经运行了太多进程,已经超过了允许他执行的最大进程数。
    fork执行失败,会向父进程返回-1,而且不创建子进程,更新errno。
    fork执行成功,向父进程返回子进程的PID,向子进程返回0。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    int main(int arg, char * args[])
    {
        pid_t child=fork();
        if(child==-1)
        {
            printf("操作系统出错!
    ");
            return -1;
        }
        if(child==0)
        {
            //此时在子进程中
            printf("child is begining!
    ");
            sleep(200);
            printf("child is end!
    ");
        }else
        {
            //此时在父进程中,child大于零,child的值就是子进程的PID
            printf("parent is begining!
    ");
            sleep(200);
            printf("parent is end!
    ");
        }
        /*
         通过观察"/proc"下的父子进程,发现父子进程共用一段代码
         */
        return 0;
    }
    当进程执行到fork()函数的时候,会复制自身,创建一个新进程,父进程,子进程都会执行fork()函数,
    子进程的代码执行将会从fork()函数开始,而不是重新将所有父进程代码执行一遍(因为这样会出现重复执行fork函数,不断的创建新进程)
    fork系统调用的特殊之处在于一段代码在不同的两个进程中运行(例如if的两个分支)
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    int main(int arg, char * args[])
    {
        int i=0;
        for(;i<2;i++)
        {
            pid_t child=fork();
        }
        /*
        这样会创建4个进程,分别是2个父进程,2个子进程
         这其实很像一棵树
        父进程A执行第一次循环,生成子进程B,此时父进程A中child=子进程B的PID;子进程B的child=0
        当父进程执行第二次循环,生成子进程C,此时父进程A中child=子进程C的PID;子进程C的child=0
        但是此时子进程B会执行fork()函数之后的代码,所以子进程B会再次执行一次fork()函数,
        此时系统会复制子进程B成为一个新的孙子进程D,那么子进程B就会变成一个父进程。
         */
        return 0;
    }
    //fork函数共享文件标识符
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(int arg, char * args[])
    {
        if(arg<2)
        {
            printf("请输入一个参数!
    ");
            return -1;
        }
        int fd=open(args[1],O_WRONLY);
        if(fd==-1)
        {
            printf("error msg:%s
    ",strerror(errno));
            return -1;
        }
        //create new process
        pid_t child=fork();
        if(child==0)
        {
            sleep(3);
            printf("child is beining
    ");
            //child process
            //write the file
            char buf[30]={0};
            int index=0;
            strcpy(buf,"fly on air!
    ");
            index=write(fd,buf,strlen(buf)+1);
            printf("write count :%d
    ",index);
            //close the file
            /*
                对close()函数加强
                close()关闭是对文件标识符的引用减一,直到对文件标识符的引用变成0,该文件才会真正关闭
                当执行fork()函数后对文件标识符fd引用就变成两个,
                fd同时被父进程和子进程所引用
                所以单独在父进程或者子进程中close()并无法关闭文件引用
                必须同时在父进程和子进程关闭引用
             */
            close(fd);
            printf("child is end
    ");
        }else
        {
            printf("parent beining
    ");
            close(fd);
            printf("parent is end
    ");
            /*
             函数名: exit()
            所在头文件:stdlib.h(如果是”VC6.0“的话头文件为:windows.h)
            功 能: 关闭所有文件,终止正在执行的进程。
            exit(0)表示正常退出,
            exit(x)(x不为0)都表示异常退出,这个x是返回给操作系统(包括UNIX,Linux,和MS DOS)的,以供其他程序使用。
             */
            exit(0);
            //程序exit(0)后面的代码都不会执行,此时进程已经退出
            printf("l am not protect!
    ");
        }
        printf("all end!
    ");
        return 0;
    }

     

        详解:程序在fork()函数之前open()打开一个文件描述符fd3,这个文件描述符指向一个文件表A(fd3类似于一个指针,指向一个文件表的内存区域),
    执行fork()函数后,当子进程中使用了文件描述符fd3时,那么Linux内核会写时拷贝fd3文件描述符到子进程中,此时子进程中的fd3文件描述符也指向
    同一个文件表A(类似于两个指针指向同一片内存),此时Linux内核会将refcnt这个值加1,表示现在有2个进程引用该文件描述符所以关闭该文件表,
    需要在父进程和子进程中分别关闭。
  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5810309.html
Copyright © 2011-2022 走看看