主要介绍Linux进程相关知识 及部分命令参考
1.概述
Linux是一个多用户、多任务的系统,能同时运行多个程序,从而产生多个进程。Linux进程中,进程和线程没有什么区别。Linux中的进程是一个数据结构,如下:
struct task_struct { // 进程状态 long state; // 虚拟内存结构体 struct mm_struct *mm; // 进程号 pid_t pid; // 指向父进程的指针 struct task_struct __rcu *parent; // 子进程列表 struct list_head children; // 存放文件系统信息的指针 struct fs_struct *fs; // 一个数组,包含该进程打开的文件指针 struct files_struct *files;};
简单来说,进程主要是:
每执行一个程序都称为一个进程,每一个进程都分配一个ID号。
每个进程都对应一个父进程,父进程可以复制多个子进程
每个进程有两种方式,前台和后台,前台指用户屏幕上可以操作,后台是实际操作
一般的系统服务都是后台进程方式存在,常驻系统中,直到关机结束。
进程主要有三种类型,用户进程(User Processes):用户账户活动、守护进程()Deamon processes):后台程序和内核进程(Kernel Processes)
内核进程仅在内核空间(kernel space)当中执行。内核进程与守护进程有些相似;它们之间主要的不同在于:内核进程对内核数据结构拥有完全的访问权限。此外,内核进程不如守护进程灵活:修改配置文件并触发重载即可修改守护进程的行为;但对于内核进程来说,修改行为则需要重新编译内核本身。
2.具体介绍
进程主要分为六种状态,分别是R/S/D/T/Z/X
2.1.运行状态 -R
只有在该状态下,进程才能在CPU上运行,其他可执行进程需要排队(一个进程最多只能出现在一个cpu队列中,这也是进程调度器主要任务)。正在CPU执行的进程和可执行尚未被跳读执行的进程统一称为TASK__RUNNING状态
2.2.可中断的睡眠状态-S
该进程需要等某个事件(如信号量、socket连接等)而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。
2.3.不可中断进的睡眠状态 -D
与task_interruptible状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。该状态进程无法kill,除了等待,另一种办法是重启操作系统。
处于uninterruptible sleep状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就被ps看到了,同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如挂载的远程文件系统已经不可访问了.—当处于uninterruptibly sleep 状态时,只有当进程从system 调用返回时,才通知signal
2.4.暂停状态或跟踪状态 -T
向进程发送一个sigstop信号,它就会因响应该信号而进入task_stopped状态。如果本身为不可中断的睡眠状态,就不相应。 如果发送sigcont信号,可以让进程从task_stoped状态恢复到task_running状态。
task_traced状态相当于在task_stopped之上多了一层保护,处于task_traced状态的进程不能响应sigcont信号而被唤醒。只能等到调试进程通过ptrace系统调用执行ptrace_cont、ptrace_detach等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复task_running状态。
当进程正在被跟踪时,它处于task_traced这个特殊的状态。“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。比如在gdb中对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于task_traced状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态
2.5.僵尸进程
进程在退出的过程中,处于TASK_DEAD状态。在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。
如果父进程结束了,init进程会自动接受,清理相关子进程。如果父进程是一个循环,那么子进程就会一直保持僵尸状态。
处理僵尸进程的办法
改写父进程
kill父进程
重启系统
2.6.退出状态
exit_dead状态是非常短暂的,几乎不可能通过ps命令捕捉到。
3.进程状态变化说明
3.1进程的初始状态
进程是通过fork系列的系统调用(fork、clone、vfork)来创建的,内核(或内核模块)也可以通过kernel_thread函数创建内核进程。这些创建子进程的函数本质上都完成了相同的功能——将调用进程复制一份,得到子进程。(可以通过选项参数来决定各种资源是共享、还是私有。)
既然调用进程处于task_running状态,则子进程默认也处于task_running状态。
另外,在系统调用调用clone和内核函数kernel_thread也接受clone_stopped选项,从而将子进程的初始状态置为 task_stopped。
3.2进程状态的变迁
两个方向:从task_running状态变为非task_running状态、或者从非task_running状态变为task_running状态
如果给一个task_interruptible状态的进程发送sigkill信号,这个进程将先被唤醒(进入task_running状态),然后再响应sigkill信号而退出(变为task_dead状态)。并不会从task_interruptible状态直接退出。
进程从非task_running状态变为task_running状态,是由别的进程(也可能是中断处理程序)执行唤醒操作来实现的。执行唤醒的进程设置被唤醒进程的状态为task_running,然后将其task_struct结构加入到某个cpu的可执行队列中。于是被唤醒的进程将有机会被调度执行。
进程从task_running状态变为非task_running状态,则有两种途径:
响应信号而进入task_stoped状态、或task_dead状态;
执行系统调用主动进入task_interruptible状态(如nanosleep系统调用)、或task_dead状态(如exit系统调用);或由于执行系统调用需要的资源得不到满足,而进入task_interruptible状态或task_uninterruptible状态(如select系统调用)。
显然,这两种情况都只能发生在进程正在cpu上执行的情况下。
4.常用命令参考:
#查看进程ps -aux |more# user 用户名称# pid 进程号# %cpu 进程占用cpu百分比# %%mem 进程占用物理内存的百分比# vsz 进程占用虚拟内存的大小# rss 进程占用物理内存的大小# tty 终端名称(后台则为?)# stat 进程状态# S:睡眠# s:会话的先导进程# N:进程拥有比普通优先级更低的优先级# R:正在运行# D:短期等待# Z:僵尸进程# T:被跟踪或者被停止# start 进程启动时间# time 使用cpu总时间# command 启动进程所用的命令和参数,如果过长会被截断显示ps -ef |more#uid 用户id#pid 进程id#ppid 父进程id#C 进程占cpu百分比#stime 进程启动时间#tty 终端名称(后台则为?)#cmd 启动进程所用的命令和参数-------------------------------------------------------------------------#查看进程树pstree#进程io相关,egpidstat -d 1 10 #进程 io读写情况 -p 某个进程#打印正在运行的进程的栈跟踪信息pstack [pid] #pstack是gdb的一部分,yum gdb即可#显示线程运行时间ps -eLo pid,lwp,pcpu |grep #LWP XXXX#其他命令,如strace #跟踪进程ptrace # 进程跟踪perf #性能分析oprofile #性能测试工具
5.进程、线程和协程
进程是资源分配的基本单位,线程是资源调度的基本单位
4.1进程
进程是操作系统对一个正在运行的程序的抽象,一个系统可同时运行多个进程,每个进程都好像独占硬件。并发指一个进程和另一个进程的指令是交错执行的。操作系统实现这种交错执行的机制称为上下文切换。
操作系统保持跟踪进程运行所需要的所有状态信息。这种状态就是上下文,包括例如PC和寄存器文件的当前值,以及主存的内容。任何时刻,但处理器系统只能执行一个进程的代码,如果操作系统决定把控制权转移到新的进程上,就会进行上下文切换。
4.2线程
一个进程可以由多个线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。进程的个体间是完全独立的,线程是彼此依存的。多进程环境中,进程终止不影响其他,多线程环境,父线程终止,全部子线程被迫终止。
linux中的线程,轻量级的进程表示。
4.3协程
协程是用户模式下的轻量级线程,更准确叫用户空间线程。协程程序是在线程里面跑的,因此协程又称微线程和纤程等。
协没有线程的上下文切换消耗。协程的调度切换是用户(程序员)手动切换的,因此更加灵活,因此又叫用户空间线程.
原子操作性。由于协程是用户调度的,所以不会出现执行一半的代码片段被强制中断了,因此无需原子操作锁。
来源:ITPUB博客
作者:luyishan- 本文固定链接: https://maimengkong.com/morejc/908.html
- 转载请注明: : 萌小白 2022年5月8日 于 卖萌控的博客 发表
- 百度已收录