精华内容
下载资源
问答
  • fork()用来创建进程fork(void)在linux中所有进程都是由init进程直接或间接创建成功:在父进程中将返回子进程的PID;子进程返回0,以区别父进程失败:父进程中返回-11 #include 2 #include 3 #include 45 int main...

    fork()

    用来创建进程fork(void)

    在linux中所有进程都是由init进程直接或间接创建

    成功:在父进程中将返回子进程的PID;子进程返回0,以区别父进程

    失败:父进程中返回-1

    1 #include

    2 #include

    3 #include

    4

    5 int main(int argc,char *argv[])

    6 {

    7 pid_t pid;

    8 if((pid=fork())==-1)

    9 printf("fork error");

    10 printf("bye\n");

    11 printf("当前进程的进程号pid:%d\n当前进程的父进程号ppid:%d\n",getpid(),getppid());

    12 return 0;

    13 }

    结果:

    [root@sun PCB]# ps aux

    root      3905  0.0  0.1 108468  1904 pts/0    S    Dec17   0:00 bash

    [root@sun PCB]# ./fork

    bye

    bye

    当前进程的进程号pid:4570

    当前进程的父进程号ppid:3905

    pid=fork()中pid的值:4571  //在父进程中将返回子进程的PID

    当前进程的进程号pid:4571

    当前进程的父进程号ppid:4570

    pid=fork()中pid的值:0  //子进程返回0,以区别父进程

    子进程中的代码在fork返回位置执行;子进程创建成功之后,和父进程同时执行,竞争系统资源,谁先执行由调度算法决定。

    父子进程

    子进程会复制父进程的几乎所有信息:子进程复制父进程用户空间所有数据;

    子进程复制父进程内核空间PCB中绝大多数数据;

    一、文件流缓冲区的资源位于用户空间,所以全部复制。即如果流缓冲区中有临时信息,都会复制到子进程的用户空间流缓冲区中。

    1 #include

    2 #include

    3 #include

    4

    5 int main(int argc,char *argv[])

    6 {

    7 pid_t pid;

    8 printf("在fork之前,有回车\n");

    9 printf("在fork之前,没有回车,getpid()——pid=%d\t",getpid());

    10 pid=fork();

    11 if(pid==0)

    12 printf("\nfork后创建的子进程getpid()——pid=%d\n",getpid());

    13 else

    14 printf("\nfork后创建的父进程getpid()——pid=%d\n",getpid());

    15 }

    [root@sun PCB]# ./streamfork

    在fork之前,有回车

    在fork之前,没有回车,getpid()——pid=5536

    fork后创建的父进程getpid()——pid=5536

    在fork之前,没有回车,getpid()——pid=5536

    fork后创建的子进程getpid()——pid=5537

    按照上面所说,子进程要在fork方法执行并返回某值后才会复制代码到子进程,子进程从返回值位置向后执行,不会执行之前的代码,但这段代码却输出了之前的代码,这就是复制了缓冲区的缘故。

    之所以出现两次输出,有两方面原因,首先是跟printf的缓冲机制有关,我们在前面说过printf("%d",i)=fprintf(stdout,"%d",i),就是说printf函数输出某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有立刻写到屏幕上。但是,只要看到有/n 则会立即刷新stdout,才能够马上打印了。

    其次就是因为复制了缓冲区。由于父进程在fork前输出的第二个printf函数时没有回车,而输出流是带缓冲的,从而该信息缓存到用户空间,在fork创建子进程后,系统为子进程复制父进程数据空间以及标准输出缓冲区,子进程刷新了输出缓冲区,将数据输出。

    二、子进程复制父进程的数据段,BSS段,代码段,堆空间,栈空间,文件描述符,但是对于文件描述符关联的内核文件表项(即struct file结构体)则是采用共享的方式

    1 #include

    2 #include

    3 #include

    4 #include

    5 #include

    6 #include

    7

    8 int main(int argc,char *argv[])

    9 {

    10 pid_t pid;

    11 intfd;

    12 int i=1;

    13 intstatus;

    14 char *ch1="hello";

    15 char *ch2="world";

    16 char *ch3="IN";

    17 if((fd=open("test.txt",O_RDWR|O_CREAT,0644))==-1)

    18 {

    19 perror("parent open");

    20 exit(EXIT_FAILURE);

    21 }

    22 if(write(fd,ch1,strlen(ch1))==-1)

    23 {

    24 perror("parent write");

    25 exit(EXIT_FAILURE);

    26 }

    27 if((pid=fork())==-1)

    28 {

    29 perror("fork");

    30 exit(EXIT_FAILURE);

    31 }

    32 else if(pid==0)

    33 {

    34 i=2;

    35 printf("in chile\n");

    36 printf("i=%d\n",i);

    37 if(write(fd,ch2,strlen(ch2)));

    38 perror("chile write");

    39 return 0;

    40 }

    41 else

    42 {

    43 sleep(1);//等待子进程先执行

    44 printf("in parent\n");

    45 printf("i=%d\n",i);

    46 if(write(fd,ch3,strlen(ch3)));

    47 perror("parent write");

    48 wait(&status);//等待子进程结束

    49 return 0;

    50 }

    51 }

    [root@sun PCB]# ./forkfilrstruct

    in chile

    i=2

    chile write: Success

    //在这里明显等待1s才出现in parent,即sleep()让父进程等待1s好让子进程完成写ch2的操作,1s后再写ch3

    in parent

    i=1

    parent write: Success

    [root@sun PCB]# cat test.txt

    helloworldIN

    从test.txt的内容可以看出,父子进程对同一个文件操作,写入数据也不覆盖,即说明父子进程共享文件偏移,因此共享文件表项

    而从变量i可以看出子进程赋值后父进程的i值不变,说明父子进程各自拥有这一变量的副本,互相不影响。

    这里对wait函数稍加介绍:

    wait(等待子进程中断或结束)

    wait()会暂时停止进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值,由参数status

    返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status 可以设成NULL。

    vfork()

    vfolk()创建新进程时不复制父进程的地址空间,而是在必要的时候才申请新的存储空间,共享父进程的代码以及数据段等

    1 #include

    2 #include

    3 #include

    4 #include

    5 #include

    6 int glob=6;    //已初始化全局变量,存放在数据段

    7 intmain()

    8 {

    9 int var;

    10 pid_t pid;

    11 var=88;   //局部变量,存放在栈

    12 printf("in beginning:\tglob=%d\tvar=%d\n",glob,var);

    13 if((pid=vfork())<0)

    14 {

    15 perror("vfork");

    16 exit(EXIT_FAILURE);

    17 }

    18 else if(pid==0)

    19 {

    20 printf("in child,modify the var:glob++,var++\n");

    21 glob++;

    22 var++;

    23 printf("in child:\tglob=%d\tvar=%d\n",glob,var);

    24 _exit(0);

    25 }

    26 else

    27 {

    28 printf("in parent:\tglob=%d\tvar=%d\n",glob,var);

    29 return 0;

    30 }

    31 }

    输出的glob,var的值相同,均是自加之后的结果,说明子进程修改后父进程跟着改变,即两者共享。

    若vfork改成fork,则子进程是自加后的结果,父进程不变,说明子进程是父进程的一份复制。

    但是由于父子空间共享内存空间,使得由子函数调用vfork创建的子进程(架设子进程为先执行函数的进程)调用其它函数或运行其他程序后会,父进程会出现段错误,如下:

    1 #include

    2 #include

    3 #include

    4 voidtest()

    5 {

    6 pid_t pid;

    7 pid=vfork();//创建子进程

    8 if(pid==-1)

    9 {

    10 perror("vfork");

    11 exit(EXIT_FAILURE);

    12 }

    13 else if(pid==0)  //子进程先运行

    14 {

    15 printf("1:child pid=%d,ppid=%d\n",getpid(),getppid());

    16 return;

    17 }

    18 else

    19 printf("2:parent pid=%d,ppid=%d\n",getpid(),getppid());

    20 }

    21 voidfun()

    22 {

    23 inti;

    24 int buf[100];

    25 for(i=0;i<100;i++)

    26 buf[i]=0;

    27 printf("3:child pid=%d,ppid=%d\n",getpid(),getppid());

    28 }

    29 intmain()

    30 {

    31 pid_t pid;

    32 test();

    33 fun();

    34 }

    1.创建主函数,申请栈空间(局部变量、返回值、参数等)

    2.调用test函数,申请test函数的栈空间

    3.test函数创建子进程,子进程先运行,在test中输出pid和ppid,清理栈空间

    4.子进程调用fun函数,覆盖原来test函数的栈空间,执行完毕后退出

    5.父进程从返回处开始执行,可是栈已经不存在了

    所以如果希望在创建的子进程中运行新的程序,则用fork()函数创建子进程,再用exec系列函数替代子进程用户空间的资源(代码、堆、栈等),内核信息基本不修改。

    execl系列

    1 #include

    2 #include

    3 #include

    4

    5 int main(int argc,char*argv[])

    6 {

    7 pid_t pid;

    8 if((pid=fork())<0)

    9 {

    10 printf("error");

    11 }

    12 else if(pid==0)

    13 {

    14 execl("/bin/ls","ls","-l","/home",(char *)0);

    15 }

    16 else

    17 printf("father ok!\n");

    18

    19 }

    [root@sun task]# ./execl

    father ok!

    [root@sun task]# 总用量 16

    drwxr-xr-x.  4 root   root   4096 11月 14 23:10 df

    drwx------. 29 hadoop hadoop 4096 9月   4 23:15 hadoop

    drwx------. 44 sun    sun    4096 12月 30 04:45 sun

    drwxr-xr-x. 12 root   root   4096 12月 30 05:01 test

    在执行execl系列函数时,默认情况下,新代码可以使用原来代码中打开的文件描述符,即执行execl时,并不关闭进程原来打开的文件

    1 #include

    2 #include

    3 #include

    4 #include

    5 #include

    6 #include

    7

    8 int main(int argc,char*argv[])

    9 {

    10 intfd,status;

    11 pid_t pid;

    12 fd=open("test.txt",O_RDWR|O_APPEND|O_CREAT,0644);//打开文件,产生一个文件描述符fd,从文件尾开始追加

    13 if(fd==-1)

    14 {

    15 perror("open");

    16 exit(EXIT_FAILURE);

    17 }

    18 printf("before child process write\n");

    19 system("cat test.txt");//创建新进程,在新进程中运行命令,直到新进程运行结束在运行父进程

    20 if((pid=fork())==-1)

    21 {

    22 perror("fork");

    23 exit(EXIT_FAILURE);

    24 }

    25 if(pid==0)

    26 {

    27 char buf[128];

    28 sprintf(buf,"%d",fd);//将文件描述符写入缓冲区

    29 execl("./newcode","newcode",buf,(char *)0);//执行newcode,把文件描述符以参数的形式传递给代码newcode,在newcode中执行对文件的追加写入工作

    30 }

    31 else

    32 {

    33 wait(&status);

    34 printf("after child_process write\n");

    35 system("cat test.txt");

    36 }

    37 }

    1 #include

    2 #include

    3 #include

    4

    5 int main(int argc,char*argv[])

    6 {

    7 inti;

    8 intfd;

    9 char *ptr="helloworld\n";

    10 fd=atoi(argv[1]);//argv[1]中的值是写入buf的fd=open("test.txt",O_RDWR|O_APPEND|O_CREAT,0644)

    11 i=write(fd,ptr,strlen(ptr));//写入fd关联的test.txt中,执行成功,说明原来的文件描述符可以使用

    12 if(i<=0)

    13 perror("write");

    14 close(fd);

    15 }

    [root@sun task]# ./system_execl

    before child process write

    我是测试文件

    after child_process write

    我是测试文件

    helloworld

    父子进程共享文件描述符:此说法,其实是父子进程共享 文件表项(父进程和子进程共享同一个file table entry)

    由于子进程是父进程的拷贝,子进程会拷贝父进程的进程描述符中的文件描述符表,可以说继承父进程的文件描述字(files_struct中的struct file *fd_array[NR_OPEN_DEFAULT]的拷贝)

    如果我们没有调用exec函数,则我们父子进程的代码段,堆栈,数据段都完全相同(因为是拷贝),所以此时我们的子进程可以使用fork()之前的fd值,虽然此时fd是属于子进程的数据段(他是之前fd的拷贝)

    一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。(不过exec类函数中有的还允许继承环境变量之类的信息。)

    所以进程的存储映像被新程序代替(也就是说,含有对方地址的套接字地址结构也丢失了),但是由于即便exec之后,打开的文件描述符依然存在,所以我们可以通过调用getpeername(fd.....)获得对端的ip和端口号

    一般来说:调用exec之前在进程中打开的描述字在exec之后还是保持打开状态的,我们可以通过fcntl函数设置FD_CLOEXEC描述字标志来关闭。此又称为文件描述字标签,默认情况是清除的

    由于exec之后,原来connfd描述字肯定没有了,所以我们必须还原这个connfd

    1、把connfd当成一个字符串,作为exec的命令行参数给新程序

    2、在调用exec之前,把某个描述字设置成connfd,(通过close(fd),然后调用dup(connfd),则根据规则,使用最小未被使用的fd,及是fd,这样fd就和connfd一样指向同一个文件表项),通常我们用0,1,2设置成connfd。

    在C程序中,文件由文件指针或者文件描述符表示。ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O函数(open, close, read, write, ioctl)使用文件描述符。下面重点来说下,文件描述符是如何工作的。

    文件描述符相当于一个逻辑句柄,而open,close等函数则是将文件或者物理设备与句柄相关联。句柄是一个整数,可以理解为进程特定的文件描述符表的索引。先介绍下面三个概念,后面讲下open、close等操作以后,文件和文件描述符产生什么关系,以及fork后文件描述符的继承等问题。

    文件描述符表:用户区的一部分,除非通过使用文件描述符的函数,否则程序无法对其进行访问。对进程中每个打开的文件,文件描述符表都包含一个条目。

    系统文件表:为系统中所有的进程共享。对每个活动的open, 它都包含一个条目。每个系统文件表的条目都包含文件偏移量、访问模式(读、写、or 读-写)以及指向它的文件描述符表的条目计数。

    内存索引节点表: 对系统中的每个活动的文件(被某个进程打开了),内存中索引节点表都包含一个条目。几个系统文件表条目可能对应于同一个内存索引节点表(不同进程打开同一个文件)。

    1、举例: 执行myfd = open( "/home/lucy/my.dat", O_RDONLY); 以后,上述3个表的关系原理图如下:

    系统文件表包含一个偏移量,给出了文件当前的位置。若2个进程同时打开一个文件(如上图A,B)做读操作,每个进程都有自己相对于文件的偏移量,而且读入整个文件是独立于另一个进程的;如果2个进程打开同一个文件做写操作,写操作是相互独立的,每个进程都可以重写另一个进程写入的内容。

    如果上面进程在open以后又执行了close()函数,操作系统会删除文件描述符表的第四个条目和系统文件表的对应条目(若指向它的描述符表唯一),并对内存索引节点表条目中的计数减1,如果自减以后变为0,说明没有其他进程链接此文件,将索引节点表条目也删除,而这里进程B也在open这个文件,所以索引节点表条目保留。

    2、文件描述符的继承

    通过fork()创建子进程时,子进程继承父进程环境和上下文的大部分内容的拷贝,其中就包括文件描述符表。

    (1)对于父进程在fork()之前打开的文件来说,子进程都会继承,与父进程共享相同的文件偏移量。如下图所示(0-1-2 表示 标准输入-输出-错误):

    系统文件表位于系统空间中,不会被fork()复制,但是系统文件表中的条目会保存指向它的文件描述符表的计数,fork()时需要对这个计数进行维护,以体现子进程对应的新的文件描述符表也指向它。程序关闭文件时,也是将系统文件表条目内部的计数减一,当计数值减为0时,才将其删除。

    (2)相反,如果父进程先进程fork,再打开my.dat,这时父子进程关于my.dat

    的文件描述符表指向不同的系统文件表条目,也不再共享文件偏移量(fork以后2个进程分别open,在系统文件表中创建2个条目);但是关于标准输入,标准输出,标准错误,父子进程还是共享的。

    展开全文
  • 0-创建进程成功,返回返回子进程idint wait(int * status)功能:将调用的进程挂起,等待子进程运行结束参数:指向整数的指针,0-子进程正常结束,非0-出现运行有误返回值:调用正常-子进程id,调用进程无子进程-调用...

    int fork()

    功能:创建一个子进程

    返回值:0-创建成功,-1-创建进程失败,>0-创建进程成功,返回返回子进程id

    int wait(int * status)

    功能:将调用的进程挂起,等待子进程运行结束

    参数:指向整数的指针,0-子进程正常结束,非0-出现运行有误

    返回值:调用正常-子进程id,调用进程无子进程-调用失败,返回-1

    int exit()

    功能:终止进程的执行

    返回值:无

    sleep(n)

    功能:进程随眠1秒

    参数:n-随眠时间

    实例代码

    1.1 父进程创建子进程,分别循环输出"I am parent."和"I am child."5次,每次输出一次后使用sleep(1)延时1s。

    #include

    #include

    /*

    1_1.c

    父进程创建子进程,分别循环输出

    "I am child."和"I am parent."

    每输出一次随眠1s。

    */

    main()

    {

    int p;

    while((p=fork())==-1);

    if(p==0)

    {/*子进程块*/

    int i;

    for(i=0;i<5;i++)

    {

    printf("I am child.\n");

    sleep(1);

    }

    }

    else

    {/*父进程块*/

    int i;

    for(i=0;i<5;i++)

    {

    printf("I am parent.\n");

    sleep(1);

    }

    }

    }

    1.2 在1.1的基础上利用exit()和wait()实现父子进程间的同步。

    #include

    #include

    #include

    /*

    简单的进程同步:

    父进程等待子进程输出后再输出

    */

    main()

    {

    int p;

    while((p=fork())==-1);

    if(p==0)

    {/*子进程块*/

    int i;

    for(i=0;i<5;i++)

    {

    printf("I am child.\n");

    sleep(1);

    }

    exit(0);

    }

    else

    {/*父进程块*/

    int i;

    for(i=0;i<5;i++)

    {

    wait(0);

    printf("I am parent.\n");

    sleep(1);

    }

    }

    }

    扩展链接

    &lbrack;apue&rsqb; 使用文件记录锁无法实现父子进程交互执行同步

    父子进程间交互执行是指用一种同步原语,实现父进程和子进程在某一时刻只有一个进程执行,之后由另外一个进程执行,用一段代码举例如下: SYNC_INIT(); , counter=; pid_t pid ...

    linux父子进程问题

    今天遇到一个linux进程启动时指定Max open files不对的问题,导致程序建立socket异常,进而导致fullgc问题,影响正常服务.所以顺带又温习了下linux下的父子进程的特性. 孤儿 ...

    Linux 父子进程实现复制文件内容到另一个文件内

    1. 子进程先拷贝前一半 ,父进程一直阻塞到子进程拷贝完再拷贝后一半 /* 子进程先拷贝前一半文件,父进程先阻塞等待子进程拷贝完前一半内容, * 然后父进程在拷贝,后一半内容 * */ #includ ...

    linux杀死进程的简单讲解

    一. 终止进程的工具kill .killall.pkill.xkill 终止一个进程或终止一个正在运行的程序,一般是通过kill .killall.pkill.xkill 等进行.比如一个程序已经死掉 ...

    &lbrack;置顶&rsqb; 简单解析linux下进程通信方法

    linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

    【Linux 进程】fork父子进程间共享数据分析

    之前我们通过fork()函数,得知了父子进程之间的存在着代码的拷贝,且父子进程都相互独立执行,那么父子进程是否共享同一段数据,即是否存在着数据共享.接下来我们就来分析分析父子进程是否存在着数据共享. ...

    【Linux 进程】之关于父子进程之间的数据共享分析

    之前我们通过fork()函数,得知了父子进程之间的存在着代码的拷贝,且父子进程都相互独立执行,那么父子进程是否共享同一段数据,即是否存在着数据共享.接下来我们就来分析分析父子进程是否存在着数据共享. ...

    linux进程通信之使用匿名管道进行父子进程通信

    管道:是指用于连接一个读进程和一个写进程,以实现它们之间通信的共享文件,又称pipe文件. 管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起 ...

    LINUX编程学习笔记&lpar;十四&rpar; 创建进程与 父子进程内存空间

    1什么是进程:进程是一个执行中的程序 执行的程序: 代码->资源->CPU 进程有很多数据维护:进程状态/进程属性 所有进程属性采用的一个树形结构体维护 ps  -a//所有进程 ps - ...

    随机推荐

    MyIsam和InnoDB的区别

    个人见解: 1.最主要的差别就是Innodb 支持事务处理与外键和行级锁.而MyISAM不支持 所以有用到事务处理和外键的,要用Innodb 2. InnoDB 中不保存表的具体行数,也就是说,执行s ...

    while do while 区别

    一.while语句的一般形式为:while(表达式)语句其中表达式是循环条件,语句为循环体.while语句的语义是:计算表达式的值,当值为真(非0)时, 执行循环体语句. int i=10; whil ...

    Git add 常见用法

    Git add   git add [参数]  [--] //作用就是将我们需要提交的代码从工作区添加到暂存区,就是告诉git系统,我们要提交哪些文件,之后就可以使用gi ...

    Awk by Example--转载

    展开全文
  • 父子进程

    2021-02-16 16:35:56
    父子进程相同处: 全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式 父子进程不同之处: 进程ID、fork返回值、父进程ID,进程运行时间、定时器、未决槽信号 父子进程间遵循...

    进程共享
    父子进程相同处:
    全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式
    父子进程不同之处:
    进程ID、fork返回值、父进程ID,进程运行时间、定时器、未决槽信号
    父子进程间遵循读时共享写时复制的原则,节省内存开销

    父子进程不共享全局变量
    shared.c

    #include<stdio.h>
    #include<unistd.h>
    
    int var=100;
    
    int main(int argc,char *argv[])
    {
        pid_t pid=fork();
        if(pid==0){
            //son
            printf("var =%d,child,pid=%d,ppid=%d\n",var,getpid(),getppid());
            var=101;
            printf("var =%d,child,pid=%d,ppid=%d\n",var,getpid(),getppid());
            sleep(3);
        }
        else if(pid>0){
            //parent
            sleep(1); //保障子进程能够修改var的值
            printf("var =%d,parent,pid=%d,ppid=%d\n",var,getpid(),getppid());
            var=102;
            printf("var =%d,parent,pid=%d,ppid=%d\n",var,getpid(),getppid());
         }
        return 0;
    }
    
    
    展开全文
  • /bin/sh#程序描述:查询进程间,父子进程,相互调用信息#作者:程晓鹏#日期:2016.12.06ps_exe_cmd="ps -ef";print_column_spliter="\t"; #打印列分隔符#查询字符串长度#参数1: 查询的字符串function QueryStrLen{v_...

    #!/bin/sh

    #程序描述:查询进程间,父子进程,相互调用信息

    #作者:    程晓鹏

    #日期:    2016.12.06

    ps_exe_cmd="ps -ef";

    print_column_spliter="\t"; #打印列分隔符

    #查询字符串长度

    #参数1: 查询的字符串

    function QueryStrLen

    {

    v_input="$1";

    v_result=`echo "${#v_input}" | awk '{print int($0)}'`;

    echo "$v_result";

    }

    #获取子字符串

    #参数1:原始字符串

    #参数2:开始的位置(从1开始)

    #参数3:长度

    function getSubStr

    {

    v_result=""; #返回值

    v_input="$1";

    v_idx="$2";

    v_len="$3";

    v_result=`echo "${v_input}" | awk '{print substr($0, vv_idx, vv_len)}' vv_idx=${v_idx} vv_len=${v_len}`;

    echo "$v_result"

    }

    #查询索引值

    #参数1:要查询的原始字符串

    #参数2:查询的关键字

    #返回值:0:代表没有搜索到;大于0,代表搜索到的索引值

    function queryIndex

    {

    v_result=0; #返回值

    v_str="$1";

    v_key="$2";

    v_str_len=$(QueryStrLen "${v_str}");

    v_key_len=$(QueryStrLen "${v_key}");

    if [ $v_str_len -gt 0 ] && [ $v_key_len -gt 0 ]; then

    v_result=`echo "${v_str}" | awk '{print index($0, q_key)}' q_key=${v_key}`;

    fi;

    echo $v_result;

    }

    #查询进程ID

    #参数1:字符串

    function queryProcessID

    {

    v_result=""; #返回结果

    v_input="$1";

    v_result=`echo ${v_input} | awk '{print $2}'`;

    echo "$v_result";

    }

    #查询父进程ID

    #参数1:字符串

    function queryPProcessID

    {

    v_result=""; #返回结果

    v_input="$1";

    v_result=`echo ${v_input} | awk '{print $3}'`;

    echo "$v_result";

    }

    #查询进程用户

    #参数1:字符串

    function queryProcessUser

    {

    v_result=""; #返回结果

    v_input="$1";

    v_result=`echo ${v_input} | awk '{print $1}'`;

    echo "$v_result";

    }

    #查询进程名称

    #参数1:要查找的字符串

    #参数2:查询的关键字

    function queryProcessName_exec

    {

    v_result=""; #返回结果

    v_input="${1}";

    v_key="${2}";

    v_input_len=$(QueryStrLen "${v_input}");

    v_idx=$(queryIndex "${v_input}" "${v_key}");

    if [ v_idx -gt 0 ]; then

    v_len=`expr "$v_input_len" - "$v_idx" + 1 | bc`;

    v_result=$(getSubStr "${v_input}" "$v_idx" "$v_len");

    fi;

    echo "${v_result}";

    }

    #获取进程名称

    #参数1:字符串

    function queryProcessName

    {

    v_result=""; #返回结果

    v_input="$1";

    v_exe_name=`echo "${v_input}" | awk '{print $8}'`; #查询进程名称,开始字符串

    v_len=$(QueryStrLen "${v_exe_name}");

    if [ $v_len -gt 0 ]; then

    v_result=$(queryProcessName_exec "${v_input}" "${v_exe_name}");

    fi;

    echo "${v_result}";

    }

    #清除所有空格

    #参数1:所有字符串

    function CleanSpace

    {

    v_in_str="$1";

    echo "$v_in_str" | sed s/[[:space:]]//g;

    }

    #打印输出信息头

    function PrintHead

    {

    column_1="user";

    column_2="pid";

    column_3="ppid";

    column_4="cmd";

    col_char="$print_column_spliter"; #列分隔符

    echo "${column_1}${col_char}${column_2}${col_char}${column_3}${col_char}${column_4}";

    }

    #打印数据

    #参数1: 字符串

    function PrintItem

    {

    line="$1"; #入参数据

    q_user=$(queryProcessUser "$line");

    q_pid=$(queryProcessID "$line");

    q_ppid=$(queryPProcessID "$line");

    q_pname=$(queryProcessName "$line");

    col_char=${print_column_spliter}; #列分隔符

    echo "${q_user}${col_char}${q_pid}${col_char}${q_ppid}${col_char}${q_pname}";

    }

    #获取子进程

    #参数1:进程ID

    function queryChildInfo

    {

    pid="$1"; #进程ID

    query_result=`${ps_exe_cmd} | grep -v grep | awk '{if($3==q_key){print $0}}' q_key=$pid`; #根据父进程ID,进行搜索

    v_len_size=$(QueryStrLen "$query_result");

    if [ $v_len_size -gt 0 ]; then

    echo "$query_result" | while read line

    do

    out=$(PrintItem "${line}");

    echo "${out}";

    q_pid=$(queryProcessID "${line}"); #获取进程ID

    queryChildInfo "$q_pid"; #进行递归调用

    done;

    fi;

    }

    #获取父进程

    #参数1:进程ID

    function queryParentInfo

    {

    pid="$1"; #进程ID

    query_result=`${ps_exe_cmd} | grep -v grep | awk '{if($2==q_key){print $0}}' q_key=$pid`; #根据进程ID,进行搜索

    v_len_size=$(QueryStrLen "$query_result");

    if [ $v_len_size -gt 0 ]; then

    echo "$query_result" | while read line

    do

    out=$(PrintItem "${line}");

    echo "${out}";

    q_ppid=$(queryPProcessID "${line}"); #获取父进程ID

    queryParentInfo "$q_ppid"; #进行递归调用

    done;

    fi;

    }

    #是否展示,标题头信息

    #参数1:是否打印标题(0:不打印; 1:打印)

    function showTitle

    {

    v_head="$1";

    if [ $v_head -gt 0 ]; then

    PrintHead; #打印信息头

    fi;

    }

    #执行查询(当前进程,及子进程)

    #参数1: 查询结果

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_run

    {

    query_result="$1";

    v_head="$2";

    v_len_size=$(QueryStrLen "$query_result");

    if [ $v_len_size -gt 0 ]; then

    showTitle "$v_head";

    echo "$query_result" | while read line #循环处理数据

    do

    tmp_line=${line}; #临时变量,递归时调用

    q_pid=$(queryProcessID "${tmp_line}");

    queryChildInfo "$q_pid"; #获取子进程信息

    out=$(PrintItem "${tmp_line}"); #打印当前进程

    echo "${out}";

    done;

    fi;

    }

    #开始执行,进程追踪

    #参数1: 查询结果

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_parent_run

    {

    query_result="$1";

    v_head="$2";

    v_len_size=$(QueryStrLen "$query_result");

    if [ $v_len_size -gt 0 ]; then

    showTitle "$v_head";

    #处理父进程,相关信息

    echo "$query_result" | while read line #循环处理数据

    do

    out=$(PrintItem "${line}"); #打印当前进程

    echo "${out}";

    q_ppid=$(queryPProcessID "${line}");

    queryParentInfo "$q_ppid"; #获取父进程信息

    done;

    fi;

    }

    #开始追踪,父子进程的,所有关系

    #参数1: 查询结果

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_all_run

    {

    query_result="$1";

    v_head="$2";

    v_len_size=$(QueryStrLen "$query_result");

    if [ $v_len_size -gt 0 ]; then

    showTitle "$v_head";

    echo "$query_result" | while read line #循环处理数据

    do

    tmp_line=${line}; #临时变量,递归时调用

    tmp2_line=${line}; #临时变量,递归时调用

    q_pid=$(queryProcessID "${tmp_line}");

    queryChildInfo "$q_pid"; #获取子进程信息

    out=$(PrintItem "${tmp_line}"); #打印当前进程

    echo "${out}";

    q_ppid=$(queryPProcessID "${tmp2_line}");

    queryParentInfo "$q_ppid"; #获取父进程信息

    done;

    fi;

    }

    #查询自身进程

    #参数1: 查询结果

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_self_run

    {

    query_result="$1";

    v_head="$2";

    tmp_result="$1"; #临时变量

    v_len_size=$(QueryStrLen "$query_result");

    if [ $v_len_size -gt 0 ]; then

    showTitle "$v_head";

    #输出进程相关信息

    echo "$tmp_result" | while read line #循环处理数据

    do

    out=$(PrintItem "${line}");

    echo "${out}";

    done;

    fi;

    }

    #根据关键字,进行查询

    #参数1:查询关键字

    #参数2:是否打印标题(0:不打印; 1:打印)

    #参数3:过滤掉的数据

    function query_key

    {

    v_key="$1"; #查询关键字

    v_head="$2";

    v_filter="$3";

    query_result=`${ps_exe_cmd} | grep "${v_key}" | grep -v "${v_filter}" | grep -v grep`;

    query_run "${query_result}" "$v_head";

    }

    #根据进程id,进行查询

    #参数1:进程ID

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_pid

    {

    p_id="$1"; #进程id

    v_head="$2";

    query_result=`${ps_exe_cmd} | grep -v grep | awk '{if($2==q_key){print $0}}' q_key=$p_id`;

    query_run "${query_result}" "$v_head";

    }

    #通过关键字,追踪进程的调用关系

    #参数1:查询关键字

    #参数2:是否打印标题(0:不打印; 1:打印)

    #参数3:过滤掉的数据

    function query_parent_key

    {

    v_key="$1"; #查询关键字

    v_head="$2";

    v_filter="$3";

    query_result=`${ps_exe_cmd} | grep "${v_key}" | grep -v "${v_filter}" | grep -v grep`;

    query_parent_run "${query_result}" "$v_head";

    }

    #通过进程id,追踪进程的父子进程,关系

    #参数1:进程

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_parent_pid

    {

    p_id="$1"; #查询关键字

    v_head="$2";

    query_result=`${ps_exe_cmd} | grep -v grep | awk '{if($2==q_key){print $0}}' q_key=$p_id`;

    query_parent_run "${query_result}" "$v_head";

    }

    #通过进程,追踪进程的调用关系

    #参数1:查询关键字

    #参数2:是否打印标题(0:不打印; 1:打印)

    #参数3:过滤掉的数据

    function query_all_key

    {

    v_key="$1"; #查询关键字

    v_head="$2";

    v_filter="$3";

    query_result=`${ps_exe_cmd} | grep "${v_key}" | grep -v "${v_filter}" | grep -v grep`;

    query_all_run "${query_result}" "$v_head";

    }

    #通过进程ID,追踪进程的父子进程,关系

    #参数1:进程ID

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_all_pid

    {

    p_id="$1"; #查询关键字

    v_head="$2";

    query_result=`${ps_exe_cmd} | grep -v grep | awk '{if($2==q_key){print $0}}' q_key=$p_id`;

    query_all_run "${query_result}" "$v_head";

    }

    #根据关键字,查询自己进程

    #参数1:查询关键字

    #参数2:是否打印标题(0:不打印; 1:打印)

    #参数3:过滤掉的数据

    function query_self_key

    {

    v_key="$1"; #查询关键字

    v_head="$2";

    v_filter="$3";

    query_result=`${ps_exe_cmd} | grep "${v_key}" | grep -v "${v_filter}" | grep -v grep`;

    query_self_run "${query_result}" "$v_head";

    }

    #根据进程ID,查询自己进程

    #参数1:进程ID

    #参数2:是否打印标题(0:不打印; 1:打印)

    function query_self_pid

    {

    p_id="$1"; #查询关键字

    v_head="$2";

    query_result=`${ps_exe_cmd} | grep -v grep | awk '{if($2==q_key){print $0}}' q_key=$p_id`;

    query_self_run "${query_result}" "$v_head";

    }

    #################################################################################################

    #################################################################################################

    #################################################################################################

    #帮助

    #参数1:命令名称

    function help

    {

    v_name="$1";

    echo "${v_name}程序,为方便查询,进程调用关系的程序。核心代码为通过ps命令,通过递归方式,查找其父子进程相关参数信息。

    执行命令格式为 ${v_name} [-a] [-i] [-p] [-0] [-n] 要查询的参数

    默认为查询入参的进程及子进程。

    可选参数如下:

    -a 搜索父子进程调用关系

    -i 通过进程ID(pid),进行搜索

    -p 查询调用的父进程调用关系

    -0 仅查询当前进程

    -n 隐藏标题输出";

    }

    #验证参数

    #参数1:参数集合,字符串

    #参数2:要验证的字符

    #返回值:0:不含有该参数; 1:含有该参数

    function valid_parameter

    {

    v_result=0;

    v_str=`echo "$1" | tr '[A-Z]' '[a-z]'`;

    v_key=`echo "$2" | tr '[A-Z]' '[a-z]'`;

    v_idx=$(queryIndex "${v_str}" "${v_key}");

    if [ $v_idx -gt 0 ]; then

    v_result=1;

    fi;

    echo $v_result;

    }

    #开始运行(参数:a)

    #参数1:是否通过,进程id,进行查询

    #参数2:是否输出标题

    #参数3:查询关键字

    #参数4:需要过滤的关键字

    function run_a

    {

    v_pid="$1";

    v_title="$2";

    v_key="$3";

    v_filter="$4";

    if [ $v_pid -gt 0 ]; then

    query_all_pid "${v_key}" "$v_title";

    else

    query_all_key "${v_key}" "$v_title" "${v_filter}";

    fi;

    }

    #开始运行(参数:p)

    #参数1:是否通过,进程id,进行查询

    #参数2:是否输出标题

    #参数3:查询关键字

    #参数4:需要过滤的关键字

    function run_p

    {

    v_pid="$1";

    v_title="$2";

    v_key="$3";

    v_filter="$4";

    if [ $v_pid -gt 0 ]; then

    query_parent_pid "${v_key}" "$v_title";

    else

    query_parent_key "${v_key}" "$v_title" "${v_filter}";

    fi;

    }

    #开始运行(参数:0)

    #参数1:是否通过,进程id,进行查询

    #参数2:是否输出标题

    #参数3:查询关键字

    #参数4:需要过滤的关键字

    function run_0

    {

    v_pid="$1";

    v_title="$2";

    v_key="$3";

    v_filter="$4";

    if [ $v_pid -gt 0 ]; then

    query_self_pid "${v_key}" "$v_title";

    else

    query_self_key "${v_key}" "$v_title" "${v_filter}";

    fi;

    }

    #开始运行(默认输出进程,以及子进程信息)

    #参数1:是否通过,进程id,进行查询

    #参数2:是否输出标题

    #参数3:查询关键字

    #参数4:需要过滤的关键字

    function run_default

    {

    v_pid="$1";

    v_title="$2";

    v_key="$3";

    v_filter="$4";

    if [ $v_pid -gt 0 ]; then

    query_pid "${v_key}" "$v_title";

    else

    query_key "${v_key}" "$v_title" "${v_filter}";

    fi;

    }

    #开始运行

    #参数1:是否执行所有(入参:a)

    #参数2:是否通过pid,进行查询(入参:i)

    #参数3:是否查询父进程相关信息(入参:p)

    #参数4:是否仅查询自己的进程(入参:0)

    #参数5:是否输出标题(入参:n)

    #参数6:查询参数

    #参数7:执行shell的名称

    function run

    {

    v_a="$1";

    v_i="$2";

    v_p="$3";

    v_0="$4";

    v_n="$5";

    v_key="$6";

    v_exe="$7";

    if [ $v_a -gt 0 ]; then

    run_a "$v_i" "$v_n" "${v_key}" "${v_exe}";

    elif [ $v_p -gt 0 ]; then

    run_p "$v_i" "$v_n" "${v_key}" "${v_exe}";

    elif [ $v_0 -gt 0 ]; then

    run_0 "$v_i" "$v_n" "${v_key}" "${v_exe}";

    else

    run_default "$v_i" "$v_n" "${v_key}" "${v_exe}";

    fi;

    }

    exe_name=$0;

    all_paras_str="";

    query_key="";

    v_head=1; #默认输出标题

    if [ $# -gt 0 ]; then

    while [ $# -ne 1 ]

    do

    para_item="$1";

    all_paras_str="${all_paras_str}${para_item}";

    shift;

    done;

    query_key="$1";

    #验证入参信息

    valid_a=$(valid_parameter "${all_paras_str}" "a"); #查看关联的,父子进程

    valid_i=$(valid_parameter "${all_paras_str}" "i"); #根据pid,进行查询

    valid_p=$(valid_parameter "${all_paras_str}" "p"); #查看父进程

    valid_0=$(valid_parameter "${all_paras_str}" "0"); #仅查询自己的进程,无关联信息

    valid_n=$(valid_parameter "${all_paras_str}" "n"); #不输出标题

    if [ $valid_n -gt 0 ]; then

    v_head=0; #关闭输出,标题信息

    fi;

    run "$valid_a" "$valid_i" "$valid_p" "$valid_0" "$v_head" "${query_key}" "${exe_name}"; #开始查询

    else

    help "$exe_name";

    fi;

    展开全文
  • linux的父子进程

    2021-05-11 12:06:53
    1)因为nginx的worker进程都是master进程fork出来的,继承了监听句柄。2)nginx实现了一个锁,work进程竞争,谁获取锁,谁accept连接。######正解!######自己顶一下######引用来自“火星人”的答案1)因为nginx的...
  • SHELL父子进程分析

    2021-05-12 10:15:45
    导言本节将就shell交互(脚本执行)过程中涉及子进程(subprocess)以及子SHELL(subshell)的部分,配以实例,进行说明。将详细讨论如下问题:subprocess和subshell是什么subprocess的产生过程是什么什么情况下会产生...
  • php父子进程通信

    2021-04-08 12:38:27
    进程demo里介绍过,如何fork子进程。 但是,谁家的孩子谁管,你fork了得记得处理啊,不然哪天捣点乱啥的,是吧。 进程进程之间通信的方式有很多种,这里用最简单的信号通信。当我们kill -9 一个进程的时候,实际...
  • 此时父子进程共享此文件的属性,引用计数==2,父子进程都执行close()才可以彻底关闭文件. 2.先复制进程在打开文件(先fork在open) 父子进程各自打开各自的文件 示意图如下: 替换进程 进程的产生:fork+exec exec函数...
  • 原地址:...CPU进程有很多数据维护:进程状态/进程属性所有进程属性采用的一个树形结构体维护ps -a//所有进程ps -aue //有效进程进程状态:(man ps)D Uninterruptible slee...
  • Linux-父子进程

    2021-04-21 22:34:40
    父子进程的全局变量读时共享,写时复制 //fork 函数测试 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> int g_var = ...
  • #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> void die(const char *msg) ... printf("In.
  • fork后的父子进程

    2021-02-24 13:51:22
    一、fork后的父子进程 由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给...
  • 2.父进程fork后,父子进程各有一套1中的变量,且代码执行是同步的,只不过储存空间不在一起,然后对父子进程的管道进行操作使之可以通信 0x01函数 write #include <unistd.h> ssize_t write(int fd, const ...
  • fork()函数功能——建立新进程html一、父子进程有独立的数据段、堆、栈,共享代码段linuxLinux中每一个进程都有4G的虚拟地址空间(独立的3G用户空间和共享的1G内核空间),fork()建立的子进程也不例外。子进程资源的...
  • 实验4Linux父子进程同步【实验目的】(1)熟悉在c语言源程序中使用linux所提供的系统调用界面的方法。(2)理解同步的概念。(3)使用系统调用wait()和exit(),实现父子进程同步。【实验原理/实验基础知识】一、同步在多道...
  • 空间,并且拷贝父进程的资源,而往往在子进程中会执行exec 调用,这样,前面的拷贝工 作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与 父进程共享地址空间(其实就是线程的概念。...
  • Java 父子进程通信

    2021-03-09 17:50:41
    由父进程创建子进程,收发消息packageorg.tango.process.parent;importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;importorg.tango.process.signal.Signal;importjava.io.*;import...
  • 1、编程时使用getpid函数获取自身的进程标识符,getppid获取父进程的进程标识符。 ...使用fork函数来判断父子进程 #include<stdio.h> #include<sys/types.h> #include<unistd.h.
  • 任何一个进程的全局变量在另一个进程中都看不到,所以进程进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核...
  • /***父子进程中管道通信**/#include #include #include #include #include #include #define SIZE 128//缓存区大小char buffer[SIZE];//缓存区int *fd;//文件描述符数组int len;//写入字符串的长度int main(){fd=...
  • } TELL_PARENT函数和TELL_PARENT函数 这两个函数主要作用就是通知父进程和子进程事件完成了,其实最后就是向父进程发SIGUSR2,向子进程发SIGUSR1信号,并且通过调用信号处理函数,把全局变量sigflag变为1。...
  • 1. shmget:共享内存创建函数,在内核空间创建缓存 ...key用于无血缘关系的进程间通信,IPC_PRIVATE用于有血缘关系的进程间通信 本节案例:父进程写入,子进程读出,是一个单向通信的过程。 root@10
  • 实验4Linux父子进程同步【实验目的】(1)熟悉在c语言源程序中使用linux所提供的系统调用界面的方法。(2)理解同步的概念。(3)使用系统调用wait()和exit(),实现父子进程同步。【实验原理/实验基础知识】一、同步在多道...
  • 本帖最后由 wg4478 于 2012-03-02 17:31:38 编辑/*父进程每3秒创建文件,子进程每4秒读取打印并删除文件*//*IncludeFiles*/#include#include#include#include#include#include#include/*MACRO*/#defineMAX5/*openfile...
  • 只输出了父进程的A,没有输出子进程的B,我想是不是父进程结束了子进程立马被杀死了。上网搜了一下,发现不是,父进程结束了子进程不会被自动杀死。 我们把子进程的死循环注释掉试一下 没用,给子进程输出加一...
  • 父子进程通过共享文件描述符,同时读写同一文件父进程首先打开一个空文件,然后调用fork创建子进程。子进程向文件写入“databuffer”,结束。父进程从文件中读取数据,但失败。总是读不到子进程已经写入到文件中的...
  • 看我下面的程序,还有问题可以baidu hi我#include #include #include #include int main(int argc, const char *argv[]){int pid, pfd[2], seq;if (argc != 2){printf("Usage:\t %s num\n", argv[0]);...
  • 参考:牛客网 C++高薪求职项目《Linux高并发服务器开发》2.3进程创建 专属优惠链接: https://www.nowcoder.com/courses/cover/live/504?coupon=AvTPnSG
  • 1.子进程继承父进程中打开的文件 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main...
  • 今天为了参加腾讯的面试,特地研究了一下...在创建成功的情况下,子进程执行返回0,是因为一个子进程只有一个父进程,所以无需知道它父进程的id,通过getppid()也就可以获取它的值,而父进程运行时,它需要知道它的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,616
精华内容 21,046
关键字:

父子进程