查看进程,认识fork
知识点
1. getpid
- 获取当前进程的进程ID(PID)。
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
返回值:
成功:返回当前进程的PID(正整数)
失败:不会失败,始终成功
示例:
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = getpid();
printf("My PID is %d\n", pid);
return 0;
}
2. getppid
- 获取当前进程的父进程ID(PPID)
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
返回值:
成功:返回父进程的PID(正整数)
失败:不会失败,始终成功
特殊情况:若父进程终止,返回 1(init/systemd 进程的PID)
示例:
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t ppid = getppid();
printf("My parent's PID is %d\n", ppid);
return 0;
}
3. fork
- 创建一个子进程,子进程是父进程的副本(复制代码、数据、堆栈等)
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回值:
成功:
在父进程中:返回子进程的PID(正整数)。
在子进程中:返回 0。
失败:返回 -1,并设置 errno(常见原因:系统进程数达到上限)。
关键点:
子进程从 fork 返回处开始执行,与父进程共享代码段。
父子进程的执行顺序由调度器决定。
子进程独立于父进程,修改变量互不影响(写时复制机制)。
示例:
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t child_pid = fork();
if (child_pid == -1) {
perror("fork failed");
return 1;
} else if (child_pid == 0) {
printf("Child process: My PID is %d, parent's PID is %d\n", getpid(), getppid());
} else {
printf("Parent process: My PID is %d, child's PID is %d\n", getpid(), child_pid);
}
return 0;
}
实操
1 查看进程属性/信息两种方式
创建一个进程
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1)
{
printf("Hello process\n");
sleep(1);
}
return 0;
}
1 命令
ps axj | head -1 && ps axj | grep myprocess | grep -v grep
命令分解
ps axj:显示所有进程的详细信息(包括无终端的进程)。
head -1 && ps axj:只输出第一行(表头),方便查看列名。
grep myprocess:筛选出包含 myprocess 的进程。
grep -v grep:排除 grep 自身进程(避免干扰)
显示:
2 查看proc文件夹
- 保存进程相关属性的目录,是一个内存及的文件系统,只有当操作系统启动的时候才会存在在磁盘上并不存在proc目录,我们刚刚创建好一个进程操作系统会自动在/proc目录下,为我们创建一个文件夹,以新增进程的PID命名
ls /proc
显示:
ls /proc/1849822
显示:
2 认识fork(创建子进程)
fork之后,创建了一个子进程,查看它们的pid
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("AAAAAAAAAAAA: pid: %d, ppid: %d\n", getpid(), getppid());
fork();
printf("BBBBBBBBBBBBBBBBBB: pid: %d, ppid: %d\n", getpid(), getppid());
sleep(1);
return 0;
}
显示:
父进程的ppid是bash
ps axj | grep 1950019
显示:
3 fork有两个返回值,且地址一样(现象)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("AAAAAAAAAAAA: pid: %d, ppid: %d\n", getpid(), getppid());
pid_t ret = fork();
printf("BBBBBBBBBBBBBBBBBB: pid: %d, ppid: %d, ret: %d, &ret: %p\n", getpid(), getppid(), ret, &ret);
sleep(1);
return 0;
}
显示:
4 创建子进程代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t ret = fork();
if (ret == 0)
{
//子进程
while(1)
{
printf("我是子进程,pid:%d,父进程pid:%d\n", getpid(), getppid());
sleep(1);
}
}
else if (ret > 0)
{
//父进程
while(1)
{
printf("我是父进程,pid:%d,父进程pid:%d\n", getpid(), getppid());
sleep(1);
}
}
else //异常情况不考虑
{}
return 0;
}
显示
5 父子进程有独立pcb,有独立性,因为代码共享而数据以写时拷贝的方式各自私有一份,保证两个进程不会互相干扰
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int x = 100;
pid_t ret = fork();
if (ret == 0)
{
//子进程
while(1)
{
printf("我是子进程,pid:%d,父进程pid:%d, %d, %p\n", getpid(), getppid(), x, &x);
sleep(1);
}
}
else if (ret > 0)
{
//父进程
while(1)
{
printf("我是父进程,pid:%d,父进程pid:%d, %d, %p\n", getpid(), getppid(), x, &x);
x = 4321;
sleep(1);
}
}
else //异常情况不考虑
{}
return 0;
}
显示