进程间关系

目录

亲缘关系

进程组关系

会话关系

孤儿态进程

守护进程

守护进程的开发标准流程:


亲缘关系

亲缘关系主要体现于父子进程,子进程父进程创建,代码继承于父进程,父进程负责回收,子进程诞生至结束父进程全程参与,这种称为强亲缘关系。

系统开机后(字符Linux系统无UI)如何创建第一个终端:

终端子进程:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    printf("son %d ,parent %d\n",getpid(),getppid());
    while(1)
        sleep(1);
}

前台才能用命令,当前这个zhong是前台所以终端不能用命令了,终端子进程默认情况下也是唯一的前台进程。

或者是有加号的是前台。

进程组关系

进程组是一种系统管理单位,进程管理器进行组划分,组转化转义,便于系统管理多进程。

一个进程组是由一个组长进程N个组员进程构成。进程组长的唯一标识,pid=pgid。

终端子进程被创建均为组长进程。

普通进程的生命周期随着使用时长持续。

进程组中直到最后一个进程终止或转移,进程组为空,系统会释放进程组。

就近原则,组长进程创建子进程,都会默认归纳到同组,成为组员进程。

进程组的成员可以转移,变为其他组成员,进程组概念与亲缘概念没有必然联系。

大多数系统不允许组长变更。

getpgrp();返回进程组id

setpgid(pid_t pid,pid_t pid);//创建进程组或转移进程组。

创建进程,组长不允许使用,组员进程可以set(getpid(),getpid()),组员申请组,组id是自己id。

转移进程,组长无法转移,setpid(3000,5000);//3000转移到5000这个组。目标组得存在,并且对目标组有权限才能转移成功。

转移到别的组代码:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
    pid_t pid;
    int i;
    for(i=0;i<3;i++)
    {
      pid=fork();
      if(pid==0)break;
    }
    if(pid>0){
    printf("parent %d,group %d\n",getpid(),getpgrp());
    while(wait(NULL)>0);
    }
    else if(pid==0){
    printf("child %d,group %d,i %d\n",getpid(),getpgrp(),i);
    if(i==2){
        sleep(5);
        printf("create group\n");
        setpgid(getpid(),getpid());
        printf("child pid %d,group %d,i %d\n",getpid(),getpid(),i);
    }
    while(1)sleep(1);
    }
    else{
        printf("fork fail\n");
        exit(0);
    }
    return 0;
}

会话关系

一个终端下可能有终端子进程和其他终端进程构成,为了便于管理这些终端进程,使用会话关系管理。

会话由一个会话发起者和若干个会话参与者构成。会话发起者标志pid=gid=sid;

会话发起者结束后按组杀死参与者,杀死终端子进程的那一组。

getsid(getpid())//返回当前进程会话id

setsid()//创建新会话(创建组->创建会话)

终端子进程无法脱离终端必然被杀死。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
    pid_t pid;
    int i;
    for(i=0;i<3;i++){
      pid=fork();
      if(pid==0)break;
    }
    if(pid>0){
    printf("parent %d,group %d\n",getpid(),getpgrp());
    while(wait(NULL)>0);
    }
    else if(pid==0){
    printf("child %d,group %d,i %d,sid %d\n",getpid(),getpgrp(),i,getsid(getpid()));
    while(1)sleep(1);
    }
    else{
        printf("fork fail\n");
        exit(0);
    }
    return 0;
}

一组都杀没了。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
    pid_t pid;
    int i;
    for(i=0;i<3;i++){
      pid=fork();
      if(pid==0)break;
    }
    if(pid>0){
    printf("parent %d,group %d\n",getpid(),getpgrp());
    while(wait(NULL)>0);
    }
    else if(pid==0){
    printf("child %d,group %d,i %d,sid %d\n",getpid(),getpgrp(),i,getsid(getpid()));
    if(i==2){
        sleep(5);
        printf("create group\n");
        setsid();
        printf("child pid %d,group %d,i %d,sid %d\n",getpid(),getpid(),i,getsid(getpid()));
    }
    while(1)sleep(1);
    }
    else{
        printf("fork fail\n");
        exit(0);
    }
    return 0;
}

关闭后6258躲过一劫。

孤儿态进程

父进程先于子进程退出,子进程失去管理,变为孤儿进程。

进程变为孤儿,父进程变更变为托管进程。所有孤儿进程结束后托管进程(upstart user可视化进程,在ubuntu14.04的版本为1init进程后续版本是init的子进程)负责处理这些僵尸进程,避免内存泄漏。

托管进程不干预孤儿进程执行,只是负责回收。

孤儿进程残留影响新进程的创建。孤儿进程的危害是弹性的,取决于孤儿进程的工作,如果孤儿进程持续申请系统资源,危害较大。

(错误信息的抛出:假如fork()失败返回-1,系统会有个errno记录,假如error=3,perror("fork error")找这个3在系统这个错误文件里找到对应错误的原因->STDERR_FIENO->使用用户自定义语句和错误信息进行拼接。)

孤儿进程是后台进程,由于父进程也没有了所以也不会出现像上面被一组杀死这种情况。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    pid_t pid;
    pid=fork();
    if(pid>0){
        exit(0);
    }
    else if(pid==0){
        while(1){
            sleep(6);
            printf("家人们谁懂啊,孤儿了\n");
        }
    }
    else{
        exit(0);
    }
    return 0;
}

这里能看出是后台进程。

这里能看见由于我们是老版本所以1号进程是托管进程。

怎么早发现早处理孤儿进程:

1.利用管道的特性处置孤儿进程,读端关闭,写端杀死。

2.kill(parent_pid,0)//测试进程是否存活。pthread_kill(tid,0)//测试线程是否存活。

要是多组的话那就很麻烦。

守护进程

守护进程又叫精灵进程,是典型的后台服务程序,其实也是孤儿进程。

守护进程的生命周期比普通进程要长,守护进程的生命周期随系统持续,开机启动,关机结束。

后台的守护进程主要职能,为主体(系统)提供持续的服务与支持。

后台服务程序,不能持续占用系统资源,会对系统造成很大的负担,所以它的工作模式都是低开销的。(抵销工作:间隔执行,定时执行,条件触发)

后台服务程序,不允许访问前台1资源。

守护进程的开发标准流程:

1.父进程创建子进程父进程退出

2.守护进程创建新会话脱离原有控制终端

3.关闭无用的描述符(STDIN_FILENO,STDOUT_FILENO)(STDERR_FILENO标准输出结果是打印在前台的,用dup2()文件描述符重定向,将错误信息重定向到特定文件中)

4.修改进程umask变为0002(修改进程掩码,避免跨平台执行出现权限异常问题)

5.修改进程的工作目录,改为根目录。(就像用u盘,将关键数据拷贝到目标主机,将服务器工作路径改为目标主机的某个路径)

6.执行守护进程的代码(任务)(低销)

7.守护进程的退出处理,资源释放等等任务。

然后配合开机启动就完成了。

开机启动:脚本队列在root下/etc/init.d/#脚本池

shell 脚本简单说明:

先看一下我们shell的版本。

再给一个执行权限。

如果是root用户下 sudo chmod 0775 jiaoben

然后./jiaoben就完事了。

#!/usr/bin/bash
#设置版本
ps aux
ls -l
date

编写一个开机启动守护进程:

开机启动脚本:

1.去找现有的脚本拷贝启动块信息,到自定义脚本中,适当修改。

2.赋予脚本执行权限

3.将自定义脚本剪切到脚本池

sudo update-rc.d shellname start 99 2.#设置启动

sudo update-rc.d shellname remove #取消启动

开机启动脚本:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          shouhuprocess
# Required-Start:    $network
# Short-Description: one process
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO

cd "/home/zzj/shouhu/"

./shouhuprocess

sudo chmod 0775 myshell

mv myshell /etc/init.d

sudo update-rc.d shellname start 99 2.#设置启动

守护进程:

#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<time.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
int process_run(){
    int timefd;
    time_t tim;
    char buf[1024];
    bzero(buf,1024);
    timefd=open("time.log",O_CREAT|O_RDWR,0664);
    if(timefd==-1){
        perror("time.log faild\n");
        exit(0);
    }
    while(1){
        tim=time(NULL);
        ctime_r(&tim,buf);
        write(timefd,buf,strlen(buf));
        bzero(buf,1024);
        sleep(3);
    }
    return 0;
}
int createprocess()
{
    int errfd;
    errfd=open("allerr",O_CREAT|O_RDWR,0664);
    if(errfd==-1){
    perror("allerr create faild\n");
    exit(0);
    }
    pid_t pid;
    pid=fork();
if(pid>0){
        exit(0);
    }
    else if(pid==0){
        //创建会话
       setsid();
       //关闭无用描述符
       close(STDIN_FILENO);
       close(STDOUT_FILENO);
       //文件重定向
       dup2(errfd,STDERR_FILENO);
       //修改进程掩码
       umask(0002);
       //修改工作路径
       chdir("./");
       //执行守护进程任务
       process_run();
       //退出处理资源释放
    }
    else{
        perror("fork fail\n");
        exit(0);
    }
    return 0;
}
int main()
{
 createprocess();
 return 0;
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Hadoop伪分布式模式下,各个进程关系如下: 1. NameNode和DataNode:NameNode是HDFS的管理节点,负责管理文件系统的命名空和元数据信息,而DataNode则负责存储数据块和提供数据访问服务。NameNode和DataNode之通过RPC(Remote Procedure Call)进行通信,NameNode会定期向DataNode发送心跳信号,以检查DataNode是否正常工作,同时也会向DataNode发出指令,如创建、删除文件等。 2. ResourceManager和NodeManager:ResourceManager是YARN的管理节点,负责管理集群中的资源和任务调度,而NodeManager则负责在每个节点上启动和监控容器,并向ResourceManager汇报节点资源使用情况以及容器的运行状况。ResourceManager和NodeManager之通过RPC进行通信,ResourceManager会向NodeManager发送指令,如启动、停止容器等。 3. NameNode和ResourceManager:NameNode和ResourceManager之也会进行通信,主要是为了协调MapReduce任务的执行。当客户端提交MapReduce任务时,ResourceManager会向NameNode请求获取输入数据的位置信息,然后将任务分配给相应的节点进行执行。执行过程中,NameNode会向ResourceManager发送任务状信息,以便ResourceManager进行监控和调度。 4. SecondaryNameNode和NameNode:SecondaryNameNode是NameNode的辅助节点,主要用于定期合并NameNode的编辑日志和FsImage文件,生成新的FsImage文件,以缩短NameNode的启动时。SecondaryNameNode和NameNode之通过RPC进行通信,SecondaryNameNode会向NameNode请求获取编辑日志和FsImage文件,然后进行合并。 这些进程关系非常复杂,但是它们的协作使得Hadoop具有了高可靠性、高可扩展性和高性能的特点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值