2024-09-18 实操层面理解进程

一、进程初探

# ps ajx | head -1
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
root@hcss-ecs:~# ps ajx | head -1; ps ajx | grep proc
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
  24696   24707   24707   24679 pts/2      24707 S+    1000   0:00 ./proc
  24756   24806   24805   24756 pts/3      24805 S+       0   0:00 grep --color=auto proc
root@hcss-ecs:~# ps ajx | head -1 && ps ajx | grep proc
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
  24696   24707   24707   24679 pts/2      24707 S+    1000   0:00 ./proc
  24756   24810   24809   24756 pts/3      24809 S+       0   0:00 grep --color=auto proc
root@hcss-ecs:~# ps ajx | head -1 && ps ajx | grep proc | grep -v grep
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
  24696   24813   24813   24679 pts/2      24813 S+    1000   0:00 ./proc

运行程序本质上是在操作系统中创建一个进程。

某些命令如 `ls` 和 `pwd` 完成操作后即终止其进程。

常驻进程(如后台服务)则持续运行,直至用户主动终止。

getpid() 是一个系统调用,用于获取当前进程的进程标识符(Process ID, PID)。

使用 kill -9 [pid] 可以立即终止指定的进程,其中 [pid] 是该进程的进程ID。此操作发送一个不可忽略的 SIGKILL 信号给目标进程,强制其立即停止运行。

二、理解 cwd

在当前项目中新建文件通常指的是在进程的当前工作目录(Current Working Directory, CWD)中创建文件。

chdir() 是一个系统调用,用于改变当前进程的工作目录。调用 chdir() 函数时需要传递一个新的目录路径作为参数,如果调用成功,则该进程后续执行的涉及文件操作的行为(如打开文件、创建文件等)都会基于这个新设置的工作目录进行。chdir() 对于需要临时改变目录进行特定操作的应用程序非常有用,但是需要注意在多线程环境下可能引发的问题,以及改变目录后对程序其他部分的影响。使用 chdir() 后,可以通过 getcwd() 函数来确认当前的工作目录是否已经更改至预期的路径。

三、/proc

/proc 并不是一个磁盘级别的文件系统,而是一个伪文件系统(virtual file system),用于向进程提供信息以及对进程进行控制。/proc 文件系统的内容由内核动态生成,反映了当前系统的状态信息,包括运行中的进程信息、系统设备信息、系统状态统计等。

pid_t getppid(void)

在Linux系统中,启动之后,新创建任何进程的时候,都是由自己的父进程创建的

因为命令是在一个由 bash 启动的shell会话中执行的。当您登录到Linux系统并输入命令时,这些命令通常是由 bash 解释并执行的。因此,如果您在一个交互式的 bash shell中运行诸如 ps 或者 pgrep 这样的命令来查找父进程ID,那么这些命令的直接父进程往往就是 bash 本身。

命令行中,执行命令/程序,本质是bash的进程创建的子进程,由子进程来执行我们的代码

使用系统调用,创建进程

fork() 是一个系统调用,用于创建一个新进程,它是Unix及类Unix操作系统中进程创建的核心机制之一。fork() 创建的新进程称为子进程,而创建它的进程称为父进程。

功能:fork() 创建一个与父进程几乎完全相同的副本(子进程),两者共享相同的程序代码但拥有独立的数据空间。

This is a proc, its pid = 29740, its ppid = 29706
This is a child proc, its pid = 29740, its ppid = 29706
This is a child proc, its pid = 29741, its ppid = 29740

PID 为 29740 的进程是由 PID 为 29706 的进程创建的。
PID 为 29741 的进程是由 PID 为 29740 的进程创建的,因此它是 PID 为 29706 的进程的“孙子”进程。

This is a proc, its pid = 29804, its ppid = 29706
This is a father proc, its pid = 29804, its ppid = 29706, ret id = 29805
This is a child proc, its pid = 29805, its ppid = 29804, ret id = 0

返回值:fork() 调用会返回两次,一次在父进程中,一次在子进程中。在父进程中返回的是子进程的PID,在子进程中返回的是0。

父 : 子 = 1 : n

fork() → 两个进程 → 父子关系 → 一般而言,代码是会共享的,但是数据是各自私有一份的

【Q】为何数据是各自私有一份的呢?

【A】进程具有很强的独立性,多个进程之间,即便是父子关系,运行时也是互不影响

用途:常用于实现进程间的并行操作、创建子进程执行不同任务等。

#include <stdio.h>
#include <unistd.h>

int main(){
	int gval = 0;
	printf("This is a proc, its pid = %d, its ppid = %d\n", getpid(), getppid());
	pid_t id = fork();

	if(id > 0){
		while(1){
			printf("This is a father proc, its pid = %d, its ppid = %d, ret id = %d, gval = %d\n", getpid(), getppid(), id, gval);
			gval += 10;
			sleep(1);
		}
	}
	else if(id == 0){
		while(1){
			printf("This is a child proc, its pid = %d, its ppid = %d, ret id = %d, gval = %d\n", getpid(), getppid(),id, gval);
			++gval;
			sleep(1);
		}
	}
	return 0;
}

以上代码展示了父进程和子进程的并行执行。父进程不断地增加一个值并打印自己的状态,而子进程则以不同的速度增加同一个值并打印自己的状态。虽然它们共享一个变量 gval,但是它们的修改是独立的,因为每个进程有自己的内存空间。

四、创建多进程简例

#include <iostream>
#include <sys/types.h>
#include <vector>
#include <unistd.h>
using namespace std;

const int num = 10;

void SubProcRun(){
	while(true){
		cout << "This is a sub proc, its pid is " << getpid() << ", its ppid is " << getppid() <<  endl;
		sleep(5);
	}
}

int main(){
	vector<pid_t> allchild;
	for(int i = 0; i < num; ++i){
		pid_t id = fork();
		if(id == 0){
			SubProcRun();
		}
		//只有父进程会在这里执行
		allchild.push_back(id);
	}
	//父进程
	cout << "Each child is above:" << endl;
	for(auto e: allchild){
		cout << e << " ";
	}
	cout << endl;
	sleep(10);
	while(true){
		cout << "This is the father proc, its pid is " << getpid() << endl;
		sleep(1);
	}	
	return 0;
}	
ps ajx | grep mproc
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
      1   48073   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48074   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48075   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48076   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48077   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48078   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48079   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48080   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48081   48072   46010 ?             -1 S     1000   0:00 ./mproc
      1   48082   48072   46010 ?             -1 S     1000   0:00 ./mproc
  72826   73911   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73912   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73913   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73914   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73915   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73916   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73917   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73918   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73919   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73920   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73911   73921   73911   72826 pts/1      73911 S+       0   0:00 ./mproc
  73756   73934   73933   73756 pts/2      73933 S+       0   0:00 grep --color=auto mproc

 五、结合系统接口理解子进程的创建

1. id 的返回值,给父(subproc)给子(0)

2. 函数 fork() 怎么会有两个返回值?

#include <unistd.h>
pid_t fork(void)
  • 函数实现里多了一个 task_struct:创建子进程的时候,子进程的 task_struct 是拷贝自父进程的
  • 调整新的 task_struct 的部分属性
  • task_struct 连入到进程列表中 子进程已经创建

父子进程都已经运行了,代码是只读共享的,各自进行了 return id; 语句的执行,所以有两个返回值

3. 一个变量,怎么会有不同的值?

(1)进行需要独立性

(2)它是怎么做到的 (to be continued)

fork 之后,谁先运行,由OS的调度器自主决定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值