【linux】进程状态

1.创建子进程

由于fork()函数给子进程和父进程返回的pid不同,我们可以根据fork的返回值来对父进程和子进程区分开来

如果返回的id是<0,则创建子进程失败,如果id==0,则说明此进程是子进程,剩下的为父进程.可以写出代码加以验证.

c 复制代码
#include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 int main()
  5 {
  6 pid_t id=fork();
  7 if(id<0)
  8 {
  9 perror("fork fail");
 10 
 11 
 12 
 13 }
 14 else if(id==0)
 15 {
 16 while(1)
 17 {  printf("我是子进程 ,pid= %d ppid= %d\n",getpid(),g    etppid());
 18 sleep(1);
 19 
 20                                                       
 21 }}
 22 else{
 23 while(1)
 24 {printf("我是父进程,pid=%d  ppid=%d\n",getpid(),getppid());
   sleep(1);
 26 
 27 
 28 
 29 
 30 
 31 }
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 }}

   
                       

创建makefile,用于代码的编译

c 复制代码
 jingchengobj:jingcheng.c
   gcc -o jingchengobj jingcheng.c
 .PHONY:clean
 clean:
   rm -f jingchengobj  

为了方便观察,我们复制ssh渠道

一份代码中两个while(1)同时进行,fork之后有两个不同的执行流


问题1:为什么给子进程返回0,给父进程返回子进程的pid?

因为对应一个父进程可以有好多个子进程,为了区分不同的子进程,来返回给父进程状态,所以给父进程返回自己的pid,而好多子进程只有一个父进程,不用区分,所以给子进程返回0;

问题2:为什么有两个返回值?


问题3:父子进程创建出来,哪个进程会先进行呢??

cpu在执行父进程,可能跑几ms,就会将父进程放到运行队列的尾巴上,可能是父进程需要向磁盘写数据,但是磁盘的队列正在执行别的,只能将父进程链接到cpu的运行队列尾巴上,等待磁盘队列空闲.所以不确谁的运行先后这个是由操作系统调度器确定的.

2.进程状态

先认识几个状态

1.创建:进程刚创建出来

2.运行:task_struct在cpu的运行队列中排队,就叫做运行态

3.阻塞:等待非cpu资源就绪,就称为阻塞状态.

阻塞解释:系统中存在着各种资源,网卡,磁盘,显卡等其他设备,其他设备也会有各自对应的运行队列,当有一个好几个经常分别要向磁盘上写不同的数据,此时的磁盘队列被占用,因为要别的经常写数据,所以会将该进程链接到cpu运行队列尾等待磁盘队列不被占用时,在将进程从运行队列尾移动到头,这个进程状态叫阻塞.

比方说我写了一个c程序,需要printf到显示屏上,我们需要等待显示队列,如果c程序写了一个scanf,我们不给输入,卡住等待键盘就绪(非cpu资源就绪)

4.挂起:

5.挂起阻塞:和cpu没关系,此时在等待非cpu资源同时,且内存不足,需要将有些进程换到swap分区去,这种进程状态叫做挂起阻塞

当os频繁的将进程的数据和代码换入换出,会影响效率,进程太多,os压力大,宕机了.


看看Linux内核源代码怎么说

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在

Linux内核里,进程有时候也叫做任务)。

下面的状态在kernel源代码里定义

bash 复制代码
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

S睡眠状态: 等待某种资源(可中断睡眠),阻塞状态

代码演示S状态

bash 复制代码
  while(1)
    {
    printf("进程正在执行,该进程的pid=%d\n",getpid());
    sleep(1);
                                                                                                                     
  }

利用命令行局部变量进行循环执行ps命令以便查看其进程状态:

c 复制代码
while :; do ps axj | head -1 && ps axj | grep jingchengobj | grep -v grep;sleep 1 ; echo "-----------------------"; done    

此时进程在向显示屏上打印东西,等待非cpu资源就绪(显示屏)

此时可以发现S状态后面有个+号,有加号说明是在前台进程,会占用bash的命令行,当我们在命令行输入其他指令时会无效,当然我们可以将其能变成后台进程,就不会占用我们的命令行了。

前台进程改后台进程

bash 复制代码
./jingchengobj &

S状态可以通过kill指令来中断

R状态: 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里

代码演示R状态

bash 复制代码
  while(1)
    {
   // printf("进程正在执行,该进程的pid=%d\n",getpid());
   // sleep(1);
                                                                                                                     
  }

当注释掉while循环里面的,就不会占用其他非cpu。

D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

c 复制代码
kill -l //指令是展示kill指令所有的选项

停止状态和睡眠状态的区别是,停止状态没有等待其他非cpu资源。

当我们运行该程序时,给个kill 19号信号来暂停进程

此时kill给个18号命令继续进程

t进程状态还有一种就是在gdb调试中,在某一行打上断点,然后运行该程序,遇到断点,停止程序,也是t状态

-g生成debug模式


X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

当一个进程结束之后,由于操作系统此时要处理好多个退出进程,还来不及来处理的这个退出的进程处于死亡状态(瞬时性特别强)不好演示

z状态:僵尸状态:进程已死,但是要将进程状态给父进程,还没给父进程,此时不允许被os释放,就叫做僵尸状态

举个例子,当使用fork创建子进程,设置子进程睡眠一会,然后退出,父进程必须等待子进程将自己的状态给父进程,此时子进程所处的状态叫做僵尸状态。

代码演示:

bash 复制代码
  #include<stdio.h>
  #include<unistd.h>
   #include<sys/types.h>
   #include<stdlib.h>

int main()
     {
        pid_t id=fork();
      if(id<0)
       {
       perror("fork fail");
     
      
      
      }
      else if(id==0)
      {
     while(1)
      {  printf("我是子进程 ,pid= %d ppid= %d\n",getpid(),g          etppid());
      sleep(3);
      break;                                                    
      
                                                            
      }
      exit(0);}
        else{
     while(1)
      {printf("我是父进程,pid=%d  ppid=%d\n",getpid(),getppid()      );
      sleep(1);
     
     }
                                                               
     }}
相关推荐
xuanzdhc1 小时前
Linux 基础IO
linux·运维·服务器
愚润求学1 小时前
【Linux】网络基础
linux·运维·网络
bantinghy2 小时前
Linux进程单例模式运行
linux·服务器·单例模式
小和尚同志3 小时前
29.4k!使用 1Panel 来管理你的服务器吧
linux·运维
帽儿山的枪手3 小时前
为什么Linux需要3种NAT地址转换?一探究竟
linux·网络协议·安全
shadon1789 天前
回答 如何通过inode client的SSLVPN登录之后,访问需要通过域名才能打开的服务
linux
小米里的大麦9 天前
014 Linux 2.6内核进程调度队列(了解)
linux·运维·驱动开发
算法练习生9 天前
Linux文件元信息完全指南:权限、链接与时间属性
linux·运维·服务器
忘了ʷºᵇₐ9 天前
Linux系统能ping通ip但无法ping通域名的解决方法
linux·服务器·tcp/ip
浩浩测试一下9 天前
渗透测试指南(CS&&MSF):Windows 与 Linux 系统中的日志与文件痕迹清理
linux·运维·windows·安全·web安全·网络安全·系统安全