个人Linux操作系统学习笔记7 - 进程理解

目录


如何判断一个程序是进程

bash 复制代码
$ ps axj | head -1 ; ps axj | grep myprocess
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
 8032  9193  9193  8032 pts/2     9193 S+    1004   0:00 ./myprocess

获得进程的pid值

使用getpid函数获得进程本身的id

使用<sys/types.h><unistd.h>

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

int main()
{
  while(1)
  {
    printf("I am a process, pid: %d\n", getpid());
    sleep(1);
  }
  return 0;
}

使用getppid获得父进程的pid

使用<sys/types.h><unistd.h>

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

int main()
{
  while(1)
  {
    printf("I am a process, pid: %d, ppid: %d\n", getpid(), getppid());
    sleep(1);
  }
  return 0;
}

何为父进程?

Linux系统中,新的进程,往往通过父进程的方式创建出来的

bash 复制代码
$ ./myprocess 
I am a process, pid: 9986, ppid: 8032
$ ./myprocess 
I am a process, pid: 9997, ppid: 8032
$ ./myprocess 
I am a process, pid: 10001, ppid: 8032

可以发现,父进程一直不变

查询发现,该进程是-bash

bash 复制代码
$ ps axj | head -1 && ps axj | grep 8032
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
 8031  8032  8032  8032 pts/2    10138 Ss    1004   0:00 -bash

结论:自己写的程序,会交给命令行解释器创建进程

-bash(命令行解释器)是命令行中执行所有程序的父进程

如何创建子进程?

创建子进程,本质是OS内部多了一个子进程(task struct + 代码和数据)

但是这个过程是一个系统调用

使用fork进行创建子进程

textile 复制代码
NAME
       fork - create a child process

SYNOPSIS
       #include <unistd.h>

       pid_t fork(void);
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  printf("I am a process, pid: %d, ppid: %d\n", getpid(), getppid());
  fork();
  printf("I am a process(fork), pid: %d, ppid: %d\n", getpid(), getppid());
  sleep(1);

  return 0;
}
bash 复制代码
$ ./myprocess 
I am a process, pid: 15728, ppid: 8032
I am a process(fork), pid: 15728, ppid: 8032
I am a process(fork), pid: 15729, ppid: 15728

可以发现,后面一句printf居然被打印了两次

因为原本的进程15728在fork();这句时创建了一个子进程15729

此时,两个进程会从fork();这行继续往下执行

因此出现了这种打印结果

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

int main()
{
  printf("I am a process, pid: %d, ppid: %d\n", getpid(), getppid());
  fork();

  while(1)
  {
    printf("I am a process(fork), pid: %d, ppid: %d\n", getpid(), getppid());
    sleep(1);
  }
  return 0;
}

bash是怎么创建子进程的?

bash 复制代码
$ which bash
/usr/bin/bash
$ ldd /usr/bin/bash
    linux-vdso.so.1 =>  (0x00007fff1d9ec000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007ffaf79f2000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007ffaf77ee000)
    libc.so.6 => /lib64/libc.so.6 (0x00007ffaf7420000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ffaf7c1c000)

可以发现bash是用c语言写的,因此内部也是通过fork创建子进程

/proc文件夹中查看进程

bash 复制代码
$ ls /proc/
1      12     17065  2016   22977  25238  26366  278    296    38   5001  541   595   7475  9021  buddyinfo  devices      fs          keys        mdstat   pagetypeinfo  softirqs       timer_stats
10     12328  17374  20986  22987  25699  26377  28     297    386  501   5726  596   771   9029  bus        diskstats    interrupts  key-users   meminfo  partitions    stat           tty
10387  13     18     21     23     25702  27     280    29732  39   509   5733  5973  8     904   cgroups    dma          iomem       kmsg        misc     sched_debug   swaps          uptime
10395  14     19     22     232    25703  270    28881  3      47   51    5745  5994  835   9040  cmdline    driver       ioports     kpagecount  modules  schedstat     sys            version
10406  16     19920  22605  24     25747  271    289    36     49   52    577   65    837   927   consoles   execdomains  irq         kpageflags  mounts   scsi          sysrq-trigger  vmallocinfo
1089   16640  2      22641  25     26     272    28900  365    5    536   580   7     839   96    cpuinfo    fb           kallsyms    loadavg     mtrr     self          sysvipc        vmstat
11     16659  20     22663  25226  26359  275    29     37     50   538   584   7468  9     acpi  crypto     filesystems  kcore       locks       net      slabinfo      timer_list     zoneinfo

其中,新建一个进程就会新建一个文件夹(名称同pid)

进程消失后,文件夹消失

文件夹内部是各种属性的记录,其中一个重要属性是cwd(currect work diratore)

这个属性会记录当前进程所处的工作路径(可执行文件的路径)

编程时所说的当前路径就是通过cwd来获取的

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

int main()
{
  FILE *fp = fopen("log.txt", "w");
  if(fp == NULL)
  {
    perror("fopen");
  }
  fclose(fp);
  return 0;
}

如何证明:

使用chdir更改cwd

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

int main()
{
  chdir("/home/suliiik/bite");
  FILE *fp = fopen("log.txt", "w");
  if(fp == NULL)
  {
    perror("fopen");
  }
  fclose(fp);
  return 0;
}

fork的返回值

前面我们没有获取fork的返回值,因此两个进程执行接下来的代码块,没有意义

因此要进行分流

text 复制代码
fork
(fork有两个返回值)
如果成功,子进程的pid会返回给父进程,0被返回给子进程;
如果失败,-1被返回给父进程,没有子进程被创建
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  printf("I am a process, pid: %d, ppid: %d\n", getpid(), getppid());
  pid_t id = fork();
  if(id < 0)
  {
    return 1;
  }
  else if(id == 0)
  {
    //子进程
    while(1)
    {
      printf("I am a child process, pid: %d, ppid: %d\n", getpid(), getppid());
      sleep(1);
    }
  }
  else
  {
    //父进程
    while(1)
    {
      printf("I am a parent process, pid: %d, ppid: %d\n", getpid(), getppid());
      sleep(1);
    }
  }

  return 0;
}

返回值用于做父子分流

为什么给子进程返回的是0,给父进程返回的是子进程的pid

父进程:子进程=1:n

子进程只需要表明自己是否创建成功即可

给父进程返回标识指定的一个子进程,方便未来控制特定的子进程

fork()是函数,为什么能返回两次?

当一个函数已经准备return了,相当于这个函数的核心功能已经完成了

fork之后,return之前,父子进程已经存在了

也就是说,父子都需要执行return

所以就能返回两次

一个id,为什么能接收两个不同的值?既==0,又>0?

这个问题暂时无法深入解答,要学习虚拟地址空间后才能理解

因为两个进程在物理内存中使用同一块内存(共享)

但是一旦某一方需要对某块内存进行修改,操作系统就会对拷贝一块新的空间(写时拷贝)

因此两个进程的id变量,虽然名称相同,但是实际物理地址不同

相关推荐
草莓熊Lotso2 小时前
【Linux网络】深入理解 HTTP 协议(四):完善 C++ HTTP 服务器:从协议原理到生产级实现
linux·运维·服务器·c语言·网络·c++·http
程序喵大人2 小时前
C++ 程序员转型 AI Infra 学习路线
c++·人工智能·学习·ai infra
问心无愧05132 小时前
ctf show web入门100
android·ide·笔记·android studio
张_boss2 小时前
从“成本中心”到“价值中心”:IT部门的价值突围
经验分享·笔记·程序人生
RainCityLucky2 小时前
Java Swing 自定义组件库分享(十一)
java·笔记·后端
段一凡-华北理工大学2 小时前
工业领域的Hadoop架构学习~系列文章14:Hadoop集群部署 - 从规划到上线的全流程实践
大数据·数据库·人工智能·hadoop·学习·架构·高炉炼铁
J.Kuchiki2 小时前
【PostgreSQL内核学习:Unique 算子源码深度解读学习】
数据库·学习·postgresql
Je1lyfish2 小时前
CMU15-445 (2025 Fall/2026 Spring) Project#4 - Concurrency Control
开发语言·数据库·c++·笔记·后端·算法·系统架构
兔老大RabbitMQ2 小时前
涉及泛型的强制转换
linux·windows·microsoft