个人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变量,虽然名称相同,但是实际物理地址不同

相关推荐
Web3探索者1 天前
可视化服务器管理和传统命令行区别是什么?新手教程:Linux 运维到底该用图形界面还是 SSH 命令行?
linux·ssh
zylyehuo1 天前
Linux系统中网线与USB网络共享冲突
linux
Sokach10153 天前
Linux Shell 脚本从零到能用:一个新手的一天学习总结
linux
AlfredZhao3 天前
Docker 容器时区不对,`timedatectl` 不存在怎么办?
linux·timezone
小宇子2B3 天前
一个 pthread_mutex_lock() 到底锁了什么——从用户态 CAS 到内核调度
操作系统
LinXunFeng4 天前
Obsidian - 使用 Share Note 分享笔记并自部署
前端·笔记·github
zzzzzz3105 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
小宇子2B5 天前
多线程 malloc 为什么会变慢——glibc 的 arena 到 bins 全景
操作系统
XIAOHEZIcode5 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
A小辣椒6 天前
TShark:Wireshark CLI 功能
linux