zoukankan      html  css  js  c++  java
  • 📹 进程管理(二)

    一、关于HUP信号

    要了解linux的HUP信号,需从hangup说起

    在Unix的早期版本中,每个终端都会通过modem和系统通讯

    当用户logout时,modem就会挂断(hang up)电话

    同理,当modem断开连接时,就会给终端发送hang up 信号来通知其关闭所有子进程

    综上所得,当用户注销(logout)或者网络断开或者终端关闭(注意:一定是终端关闭,不是单纯的exit退出时)终端都会收候到linux HUP信号(hangup)信号,然后终端在结束前会关闭有子进程。

    如果想让进程在后台一直运行,不要因为用户注销(logout)或者网络断开或者终端关闭而被一起干掉,有两种解决方案

    • 方案一:让进程忽略linux HUP信号
    • 方案二:让进程运行在新的会话里,从而成为不属于此终端进程,就不会在当前终端挂掉的情况下一起被带走

    1.nohup命令

     针对方案一;可以使用nohup命令,nohup的用途就是让提交的命令忽略hangup信号,该命令通常与&符号一起使用

    nohup的使用是十分方便的,只需要在要处理的命令前加上 nohup即可,但是nohup命令命令会从终端解除进程的关联,进程会丢掉STDOUT,STDERR的链接。标准输出和标准错误缺省会被重定向到nohup.out文件中。一般在结尾加上"&"来将命令同时放入后台运行,也可以用">filename 2>&1"来更改缺省的重定向文件名

    2.setsid命令

    针对方案1,我们还可以用setsid命令实现,原理与3.1是一样的,setid是直接将进程的父pid设置成1,即让运行的进程归属于init的子进程,那么除非init结束,该子进程才会结束,当前进程所在的终端结束后并不会影响进程的运行

    # 1、在终端2中执行命令
    [root ~]# setsid ping www.baidu.com # 也可以在后面加&符号
    
    # 2、关闭终端2
    
    # 3、在终端1中查看
    [root ~]# ps -ef |grep [p]ing
    root 102335 1 0 17:53 ? 00:00:00 ping www.baidu.com

    3.在子shell中提交任务

    # 1、在终端2中执行命令
    [root ~]# (ping www.baidu.com &) # 提交的作业并不在作业列表中
    
    # 2、关闭终端2
    
    # 3、在终端1中查看
    [root ~]# ps -ef |grep [p]ing
    root 102361 1 0 17:55 ? 00:00:00 ping www.baidu.com
     
    可以看到新提交的进程的父ID(PPID)为(init进程的PID),并不是当前终端的进程id。因此并不属于当前终端的子进程,从而也就不会受到当前终端的linux HUP信号影响了

    4.screen命令

    # 1.运行命令
    方式一:开启一个窗口名,也可以不指定
    [root ~]# screen -S tom_dsb 
    '''
    Screen将创建一个执行shell的全窗口,执行任意shell程序,在该窗口中输入exit则退出该窗口,如果此时,这是该screen会话的唯一窗口,该screen会话退出,否则screen自动切换到提前一个窗口
    '''
     方式二:screen命令后跟要执行的程序
    [root ~]# screen vim test.txt
    '''
    Screen创建一个执行vim test.txt的单窗口会话,退出vim将退出该窗口/会话
    '''
    # 原理分析
    screen程序会帮我们管理运行的命令,退出screen,命令还会继续运行,若关闭screen所在的终端,则screen程序的ppid变为1,所以screen不会死掉,对应着它帮我们管理的命令也不会退出
    
    
    # 4.重新连接会话
    在终端1中运行
    [root~]# screen
    [root ~]# n=1;while true;do echo $n;sleep 1;((n++));done
    [root ~]# 按下ctrl+a,然后再按下ctrl+d,注意连贯,受别哆嗦
    [root ~]#此时可以关闭整个终端,运行的程序并不会结束 
    
    打开一个新的终端
    [root ~]# screen -ls
    There is a screen on:
    109125.pts-0.egon (Detached)
    1 Socket in /var/run/screen/S-root.
    [root ~]# screen -r 109125 # 会继续运行
     
    
    注:如果开始就使用了screen -S  xxx指定了名字,那么我们其实可以直接screen -r xxx,就不需要去找进程id了

    screen常用参数选项

    常用命令选项:
    -c file ֵ                 使用配置文件file,而不使用默认的$HOME/.screenrc
    -d|-D [pid.tty.host]     不开启新的screen会话,而是断开其他正在运行的screen会话
    -h num                   指定历史回滚缓冲区大小为num行
    -list|-ls                列出现有的screenտ会话,格式为pid.tty.host
    -d -m                    启动一个开始就处于断开模式的会话
    -r [pid.tty.host]        重新连接一个断开的会话
    -S sessionname           创建screen会话时为会话指定一个名字
    -v                       显示screen版本信息
    -wipe [match]            同 -list,但删掉那些无法连接的会话
    -x                       会话共享演示

    查看网络状态netstat命令

    [root ~]# netstat -tnlp # 查看正在监听的,且使用tcp协议的进程
    -t tcp协议
    -u udp协议
    -l listen
    -p PID/Program name
    -n 不反解,不将IP地址解析为主机名,不讲端口号解析成协议名(80------->http)
    
    
    示例
    [root ~]# netstat -an |grep :22
    [root ~]# netstat -an |grep :80
    [root ~]# lsof -i:22

    二、proc文件系统

    • [root@localhost ~]# du -sh /proc
          cpu:/proc/cpuinfo
    [root@localhost ~]# grep "processor" /proc/cpuinfo # 逻辑cpu个数
    processor : 0
    [root@localhost ~]# grep "physical id" /proc/cpuinfo # 物理cpu个数
    [root@localhost ~]# grep "cpu cores" /proc/cpuinfo # cpu核数
    
    cpu cores : 1
     
    [root@localhost ~]# cat /proc/cpuinfo 
    ==flags
    lm (64位)
    vmx 支持虚拟化 Intel
    svm 支持虚拟化 AMD
    [root@localhost ~]# egrep --color 'lm|vmx|svm' /proc/cpuinfo 
    [root@localhost ~]# lscpu

    内存:/proc/meminfo

    查看内存
    [root ~]# less /proc/meminfo
    [root ~]# free -wm
                 total     used     free     shared     buffers 
    cache available
    Mem:     1980     192     1713         9            0 
    74 1671    
    Swap:    1023         0     1023
    [root ~]# free -m
                 total     used     free     shared     buff/cache 
    available
    Mem:     1980     192     1713         9             74 
    1672
    Swap:     1023         0    1023                            

    内核启动参数:/proc/cmdline

    [root@localhost ~]# cat /proc/cmdline
    BOOT_IMAGE=/vmlinuz-3.10.0-1127.13.1.el7.x86_64 root=UUID=84b5cfa6-b0dc-4d7aa8fd-0302f0eb2f04 ro rhgb quiet LANG=zh_CN.UTF-8
    
    [root@localhost ~]# uptime
     17:42:40 up 1 day, 1:33, 2 users, load average: 0.00, 0.01, 0.05
            注:当卸载/proc后
    [root@localhost ~]# umount /proc -l
    # 下述命令都不可用
    free -m
    uptime
    lscpu
    toop
    
    
    重新挂载
    [root@localhost ~]# mount -t proc proc /proc/
    -t proc    指定文件系统的类型
    proc       文件系统,虚拟文件系统
    /proc      挂载点

    三、管理后台进程

    [root@localhost ~]# sleep 5000 &  #运行程序(时),让其在后台执行
    [1] 31143
    [root@localhost ~]# sleep 4000 # ^z,将前台的程序挂起(暂停)到后台
    [root@localhost ~]# jobs # 中括号内的编号就是作业编号, %1代表作业1
    [1]- 运行中                sleep 5000 &
    [2]+ 已停止                sleep 4000
    [root@localhost ~]# bg %2 # 让作业2在后台运行
      [2]+ sleep 4000 &
      [root@localhost ~]# fg %1 # 将作业1调回到前台
      [root@localhost ~]# jobs
      [2]+ 运行中              sleep 4000 &
      [root@localhost ~]# kill %2
    nohup
    加在一个命令的最前面,表示不挂断的运行命令

     四、管道

    1、什么是管道

    管道用于进程间通信

    [root@localhost ~]# ps aux |grep "httpd"
    [root@localhost ~]# yum list |grep nginx

    详细的说,管道操作符号“|”主要用来链接另两个命令,将左侧的命令的标准输出,交给右侧命令的标准输入

    PS:无法专递标准错误输出置后者命令

    格式:cmd1 | cmd2 [...|cmdn]

     2、管道流程图

     3、管道应用示例

    例1:统计当前/etc/passwd中用户使用的shell类型
    [root@localhost ~]# awk -F: '{print $7}' /etc/passwd | sort |uniq -c
     2 /bin/bash
     1 /bin/sync
     1 /sbin/halt
     40 /sbin/nologin
     1 /sbin/shutdown
    
    
    
    例2:统计网站的访问情况
    [root@localhost ~]# netstat -an |grep :80 |awk -F":" '{print $8}'|sort |uniq -
    c 
    
    
    例3:答应当前所有IP
    [root@localhost ~]# ip addr |grep 'inet ' |awk '{print $2}' |awk -F"/" '{print
    $1}'
    127.0.0.1
    192.168.12.21
    192.168.122.1
    ֺ
    
    例4:打印根分区已用空间的百分比
    [root@localhost ~]# df -P|grep '/$' |awk '{print $5}'|awk -F"%" '{print $1}'
    50
    ֺ
    
    
    例5:ip top 10
    #思路:打印所有访问过来的IP |排序|去重|倒叙排列|取前10
    [root ~]# awk '{print $1}' access.log |sort |uniq -c |sort -rn|head
    12049 58.220.223.62
    10856 112.64.171.98
    1982 114.83.184.139
    1662 117.136.66.10
    1318 115.29.245.13
    961 223.104.5.197
    957 116.216.0.60
    939 180.111.48.14
    871 223.104.5.202
    869 223.104.4.139

    4、管道中的tree技术

     重定向与tee他们在使用过程中有什么区别

    [root ~]# date > date.txt #直接将内容写入date.txt文件中
    [root ~]# date |tee date.txt #命令执行会输出至屏幕,但会同时保存一份至date.txt文件中
    5、xargs参数传递,主要让一些不支持管道的命令可以使用管道技术
    [root ~]# which cat|xargs ls -l
    [root ~]# ls |xargs rm -fv
    [root ~]# ls |xargs cp -rvt /tmp/ -౲-> ls | xargs -I {} cp -rv {} /tmp/
    [root ~]# ls |xargs mv -t /tmp/ -౲-> ls | xargs -I {} mv {} /tmp五、 

    五、僵尸进程与孤儿进程

    1、什么是僵尸进程

    僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源

    2、僵尸进程残存的数据是否需要回收

    需要回收,僵进程毕竟只是linux系统的机制,为父进程准备数据,置于回收操作,应该是父进程觉得自己无需查看僵尸进程的数据,留着也无用,所以就会发起wait /waitpid来通知linux操作系统来清理掉僵尸进程

    3、僵尸进程是怎么出现的

    1、linux系统自带一些优秀的开源软件,这些软件在开启子进程时,父进程内部都会调用wait/waitpid来通知操作系统及时回收僵尸进程,所以一般看不到

    2、一些资深的程序员开发应用程序时,他们知道父进程要对子进程负责,会考虑及时回收问题,有时候可能会遇见[root ~]# ps aux | grep [Z]+

    3、一些技术较差的程序员并不知道僵尸进程,没有考虑回收问题,子进程会不停产生,父进程也不结束,所以系统中就会堆积许多的僵尸进程,占用大量pid,影响正常程序的启动

    4、如何清理僵尸进程

    1、通知父进程,调用wait/waitpid来清理子进程 kill -CHLD  父进程ID

    2、直接杀死父进程,僵尸进程就会被超级进程(init或systemd)接管,超级系统会调用wait/waitpid来让操作系统清理僵尸进程

    示例:

    =====================窗口1======================
    [root ~]# cat test.py 
    #coding:utf-8
    from multiprocessing import Process
    import os
    import time
    
    def task():
               print("father--->%s son--->%s" %(os.getppid(),os.getpid()))
    
    if __name__ == "__main__":
         p1=Process(target=task)
         p2=Process(target=task)
         p3=Process(target=task)
         p1.start()
         p2.start()
         p3.start()
         print("main--->%s" %os.getpid())
         time.sleep(10000)
    [root ~]# python test.py &
    [5] 104481
    [root ~]# main--->104481
    father--->104481 son--->104482
    father--->104481 son--->104483
    father--->104481 son--->104484
    
    
    
    =====================窗口2======================
    [root ~]# ps aux |grep Z
    USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
    root 104482 0.0 0.0 0 0 pts/2 Z 18:24 0:00 [python]
    <defunct>
    root 104483 0.0 0.0 0 0 pts/2 Z 18:24 0:00 [python]
    <defunct>
    root 104484 0.0 0.0 0 0 pts/2 Z 18:24 0:00 [python]
    <defunct>
    root 104488 0.0 0.0 112828 960 pts/4 R+ 18:24 0:00 grep --
    color=auto Z

    5、孤儿进程

    父进程先结束了运行,而父进程产生的子进程依然在运行,这就是所谓的孤儿进程,孤儿进程会被超级进程收养,并由超级进程对他们完成状态收集工作
    
    测试
    import os
    import sys
    import time
    pid = os.getpid()
    ppid = os.getppid()
    print 'im father', 'pid', pid, 'ppid', ppid
    pid = os.fork()
    #执行pid=os.fork() 则会生成一个子进程
    #返回值pidํ有两种值:
    #         如果返回的pid值为=0,表示在子进程当中
    #         如果返回值pid值为>0,表示在父进程当中
    if pid > 0:
         print 'father died..'
         sys.exit(0)
    
    #保证主线程序退出完毕
    time.sleep(1)
    print 'im child', os.getpid(), os.getppid()
    
    执行文件,输出结果
    im father pid 32515 ppid 32015
    father died..
    im child 32516 1
    
    此时,子进程已被超级进程接收,只存在孤儿进程,周期结束自然会被清理
  • 相关阅读:
    kubernetes进阶(一) kubectl工具使用详解
    二进制安装kubernetes(七) 部署知识点总结
    1024程序员节:这就是国内开发者的现状?
    php 伪协议
    浅谈 PHP 与手机 APP 开发(API 接口开发)
    比RBAC更好的权限认证方式(Auth类认证)
    PHP获得毫秒数
    2020年PHP面试题附答案(实战经验)
    分享几套2019年各大公司最新的PHP面试题,几斤几两一试便知
    PHP面试题2019年百度工程师面试题及答案解析
  • 原文地址:https://www.cnblogs.com/ChuangShi-HolySpirit/p/13934118.html
Copyright © 2011-2022 走看看