2、进程管理
程序员文章站
2022-06-24 20:35:27
...
1、进程控制块PCB
我们知道,每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。
/usr/src/linux-headers-3.16.0-30/include/linux/sched.h文件中可以查看struct task_struct 结构体定义。其内部成员有很多,我们重点掌握以下部分即可:
* 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。
* 进程的状态,有就绪、运行、挂起、停止等状态。
* 进程切换时需要保存和恢复的一些CPU寄存器。
* 描述虚拟地址空间的信息。
* 描述控制终端的信息。
* 当前工作目录(Current Working Directory)。
* umask掩码。
* 文件描述符表,包含很多指向file结构体的指针。
* 和信号相关的信息。
* 用户id和组id。
* 会话(Session)和进程组。
* 进程可以使用的资源上限(Resource Limit)。
2、进程控制的一些相关函数
1、fork函数用于创建一个子进程。
pid_t fork(void); 失败返回-1;成功返回:① 父进程返回子进程的ID(非负) ②子进程返回 0
pid_t类型表示进程ID,但为了表示-1,它是有符号整型。(0不是有效进程ID,init最小,为1)
返回值:不是fork函数能返回两个值,而是fork后,fork函数变为两个,父子需【各自】返回一个。
2、getpid函数获取当前进程ID
pid_t getpid(void);
3、getppid函数获取当前进程的父进程ID
pid_t getppid(void);
4、区分一个函数是“系统函数”还是“库函数”依据:
1>、是否访问内核数据结构
2>、是否访问外部硬件资源
二者有任一 → 系统函数;
二者均无 → 库函数
3、进程共享
父子进程之间在fork后。有哪些相同,那些相异之处呢?
刚fork之后:
父子相同处: 全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方 式...
父子不同处: 1.进程ID 2.fork返回值 3.父进程ID 4.进程运行时间 5.闹钟(定时器) 6.未决信号集
似乎,子进程复制了父进程0-3G用户空间内容,以及父进程的PCB,但pid不同。真的每fork一个子进程都 要将父进程的0-3G地址空间完全拷贝一份,然后在映射至物理内存吗?
当然不是!父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。
重点注意!躲避父子进程共享全局变量的知识误区!
【重点】:父子进程共享:1. 文件描述符(打开文件的结构体) 2. mmap建立的映射区 (进程间通信详解)
特别的,fork之后父进程先执行还是子进程先执行不确定。取决于内核所使用的调度算法。
4、例子
循环创建子进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
int i;
pid_t pid;
printf("xxxxxxxxxx\n");
for(i = 0; i < 5; i++)
{
pid = fork();
if(pid == -1)
{
perror("fork() error:");
exit(1);
}else if(pid == 0)
{
break;
}
}
sleep(i);
if(i < 5)
{
sleep(1);
printf("I'm %d child, pid = %u\n", i + 1, getpid());
}else
{
sleep(1);
printf("I'm parent , pid = %u\n", getpid());
}
return 0;
}
上一篇: 工具类中注入service和dao