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个进程引用该文件描述符所以关闭该文件表,
    需要在父进程和子进程中分别关闭。
  • 相关阅读:
    代码点与代码单元
    IIS最大并发连接数
    PhoneGap:JS跨域请求
    字符串长度
    android学习笔记:adb更换端口后成功启动
    java学习笔记:eclipse的workspace和working set
    java学习笔记:Eclipse打开现有项目
    java学习笔记:文件名区分大小写
    mysql学习笔记:存储过程
    mySql学习笔记:比sql server书写要简单
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5810309.html
Copyright © 2011-2022 走看看