qidao123.com技术社区-IT企服评测·应用市场

标题: Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解) [打印本页]

作者: 河曲智叟    时间: 2024-6-28 23:51
标题: Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解)
Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解)
上次讲了一下inux:冯诺依曼体系结构、操作系统、初识进程


  

1.查看进程

1.1预备工作

先写好代码:
  1. #include<stdio.h>
  2. #include<unistd.h>
  3. int main()
  4. {
  5.     while(1)
  6.     {
  7.         printf("I'm a process\n");
  8.         sleep(2)
  9.     }//写一个死循环,没两秒打印一次
  10.     return 0;
  11. }
复制代码
makefile文件也写好:
  1. mycode:code.c
  2.         gcc -o $@ $^ -std=c99
  3. .PHONY:clean
  4. clean
  5.         rm -f mycode
复制代码
1.2 指令:ps—表现当前系统中运行的进程信息

ps 是一个常用的 Unix/Linux 下令,用于表现当前系统中运行的进程信息。它的名称泉源于 “process status”(进程状态)的缩写。通过 ps 下令,您可以查看正在运行的进程的各种信息,例如进程 ID、CPU 利用环境、内存占用、进程状态等。
常用的 ps 下令选项和参数:
   
  综合来说,ps -ajx 下令会列出当前系统中所有进程的具体信息,包括进程的作业信息以及其他相干信息。
  常见的 ps 下令用法包括:


   在输出中,第一个进程是你的可执行文件 mycode 的进程,第二个进程是由于你利用了 grep 下令进行字符串匹配而产生的 grep 进程
  具体来说:
  
  终止后:

1.3查看进程属性

   进程的属性都在task_struct 里,而task_struct是操作系统内部的数据,我们想要访问内部的数据只能通过系统调用
  1. #include<stdio.h>
  2. #include<unistd.h>
  3. #include<sys/types.h>
  4. int main()
  5. {
  6.     pid_t id =getpid();
  7.     while(1)
  8.     {
  9.         printf("I'm a process,pid:%d\n",id);
  10.         sleep(2);
  11.     }//写一个死循环,没两秒打印一次
  12.     return 0;
  13. }
复制代码
  getgid() 函数是一个系统调用,用于获取调用进程的有用组 ID(Group ID)。在 Linux 中,每个进程都属于一个或多个组,getgid() 函数返回调用进程的有用组 ID。其函数原型定义在 <unistd.h> 头文件中:
  1. #include <unistd.h>
  2. gid_t getgid(void);
复制代码
其中,gid_t 是一个范例,通常是一个无符号整数范例,用于表现组 ID。
  1.4通过 /proc 系统文件夹看进程

在Linux系统中,/proc文件系统提供了关于运行中进程的具体信息。你可以通过查看/proc文件系统中的特定目录和文件来获取有关进程的信息。下面是一些你可以在/proc文件系统中找到的有关进程的信息:


2.父进程与子进程

2.1先容

   在操作系统中,当一个进程(称为父进程)创建另一个新进程(称为子进程)时,父子进程之间创建了一种特殊的关系。这种关系具有以下特点和行为:
    
    
    
  几乎所有进程都是由其他进程创建的,因为通常环境下,操作系统启动时会先创建一个初始进程(通常是init进程或systemd),然后其他进程都是由这些初始进程创建的。但是,也有一些特殊环境下的进程,好比内核线程和保卫进程,它们可能是由操作系统内核直接创建的,而不是由其他进程创建的。总体而言,大多数进程都是有其父进程创建的。
  2.2getpid() \getppid()

父进程和子进程之间的关系是一个重要的概念,它们之间的关系可以通过系统调用来获取。在Unix/Linux系统中,可以利用 getpid() 系统调用来获取当前进程的PID,利用 getppid() 系统调用来获取当前进程的父进程的PID。
以下是这两个系统调用的扼要分析:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main() {
  4.     pid_t pid = getpid();      // 获取当前进程的PID
  5.     pid_t ppid = getppid();    // 获取当前进程的父进程的PID
  6.     printf("PID: %d\n", pid);
  7.     printf("PPID: %d\n", ppid);
  8.     return 0;
  9. }
复制代码
2.3 fork()函数—通过系统调用创建进程

   我们要创建一个进程,那一定涉及到访问操作系统的内部数据,肯定也需要利用系统调用
  fork 是一个系统调用(也是库函数),用于创建一个新的进程。它会复制调用进程(父进程)的内存和上下文,包括代码段、数据段、堆栈等,然后将这个副本分配给新创建的进程(子进程)。fork 系统调用的原型通常定义在 <unistd.h> 头文件中。
  1. #include <unistd.h>
  2. pid_t fork(void);
复制代码
  pid_t 是一个范例,用于表现进程 ID,fork 函数返回的是一个 pid_t 范例的值。
  
  在 fork 调用后,父子进程都会继续执行 fork 调用之后的指令,但是它们会在不同的地点空间中运行,即它们各自拥有独立的内存空间。这意味着,父进程和子进程之间的数据是相互独立的,任何一个进程对内存的修改都不会影响到另一个进程。
父子进程代码共享的原理是采用写时拷贝(copy-on-write)。在 fork 调用后,操作系统并不会立即复制父进程的内存给子进程,而是让父子进程共享同一段内存空间。只有当其中一个进程试图修改共享的内存时,操作系统才会复制该内存页,确保修改不会影响到其他进程。这样做可以节省内存,并提高效率。
fork()函数疑问

fork 函数在调用后会返回两次,这是因为它是一个复制当前进程的系统调用。下面是对这两个返回值的表明:
利用fork()函数

  1. #include<stdio.h>
  2. #include<unistd.h>
  3. #include<sys/types.h>
  4. int main()
  5. {
  6.     printf("before fork:I'm a process, pid:%d, ppid:%d\n",getpid(),getppid());
  7.     sleep(1);
  8.     pid_t id=fork();
  9.     if(id<0) return 1;//说明创建失败
  10.     else if(id==0)
  11.     {
  12.         //只有子进程能进这里,我们就可以让子进程做自己的事
  13.         printf("after fork:I'm a child process, pid:%d, ppid:%d\n",getpid(),getppid());
  14.         sleep(2);
  15.     }
  16.     else
  17.     {
  18.         //只有父进程能进这里
  19.         printf("after fork:I'm a father process, pid:%d, ppid:%d\n",getpid(),getppid());
  20.     }
  21.     return 0;
  22. }
复制代码

3.进程状态

3.1进程列队

   我们首先要知道:进程不是不停在运行的。进程放在了CPU上,也不是不停会运行的,可能在等待某种软硬件资源
  而且计算机的资源相对来说不停是不敷的,那么必然出现进程列队的环境,那么列队是怎么个排法呢?
  
  

3.2课本上进程状态的表述——运行、阻塞、挂起

在操作系统中,进程的状态可以分为多种,常见的包括运行、阻塞和挂起。每种状态都对应着一个状态队列,用于存储处于相应状态的进程
     
    
  运行

     
    
    
  

阻塞

   
  
  1. #include<stdio.h>
  2. int main()
  3. {
  4.     int a=0;
  5.     scnaf("%d",&a);
  6.     printf("%d",a);
  7.     return 0;
  8. }
复制代码

   
    这个过程:
    挂起

     3.3Linux中状态初步认识

   一个进程可以有几个状态(在Linux内核里,进程偶然候也叫做任务)进程的状态通常由几个不同的状态标识符表现。以下是一些常见的进程状态及其在内核源代码中的定义:
  1. static const char* const task_state_array[] =
  2. {
  3.         "R (running)", /* 0 */
  4.         "S (sleeping)", /* 1 */
  5.         "D (disk sleep)", /* 2 */
  6.         "T (stopped)", /* 4 */
  7.         "t (tracing stop)", /* 8 */
  8.         "X (dead)", /* 16 */
  9.         "Z (zombie)", /* 32 */
  10. };
复制代码
  
  
好啦这次就到这里啦!!!也是才结束51假期,渴望51数学建模能拿个不错的奖项吧
感谢大家支持

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4