目录:
1.了解进程的相关概念
2.掌握fork/getpid/getppid函数使用
3.掌握ps/kill命令使用
4.掌握execl/execlp函数的使用
5.什么是孤儿进程、僵尸进程
6.掌握wait函数使用
7.掌握waitpid函数的使用
进程共享
进程表示如下图所示,一个a.out程序也即是一个进程。
父子进程之间在fork之后的异同:
- 相同点:全局变量、data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式…等。
- 不同之处:父子进程 1.进程id、2.fork返回值、3.父进程id、4.程序运行时间、5.闹钟(定时器)、6.未决信号集
总的来说,子进程复制了父进程0-3G用户空间内容,以及父进程的PCB,但是pid不同。每fork一个子进程都要将父进程的0-3G地址空间完全拷贝一份,然后再映射至物理内存吗??
当然不是的!!!
父子进程间遵循 读时共享、写时复制 的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。
练习:编写程序测试,父子进程是否共享全局变量。
#include<stdio.h>
#include<unistd.h>
int var = 100;
int main()
{
pid_t pid = fork();
if(pid == 0)
{
//子进程
printf("var=%d,child,pid=%d,ppid=%d\n",var,getpid(),getppid());
//子进程改变全局变量var的值
var = 10001;
printf("var=%d,child,pid=%d,ppid=%d\n",var,getpid(),getppid());
sleep(3);
printf("var=%d,child,pid=%d,ppid=%d\n",var,getpid(),getppid());
}
else if(pid > 0)
{
//父进程
sleep(1); //保证子进程能够有时间修改var的值
printf("var=%d,parent,pid=%d,ppid=%d\n",var,getpid(),getppid());
var = 9999;
printf("var=%d,parent,pid=%d,ppid=%d\n",var,getpid(),getppid());
}
return 0;
}
输出:
~$ gcc fork_shared.c
~$ ./a.out
var=100,child,pid=12380,ppid=12379
var=10001,child,pid=12380,ppid=12379
var=100,parent,pid=12379,ppid=11350
var=9999,parent,pid=12379,ppid=11350
var=10001,child,pid=12380,ppid=1622
execl/execlp函数的使用
exec函数族,exec函数一旦调用成功即执行新的程序,不返回,只有失败才返回,错误值-1。所以通常直接在exec函数调用后直接调用perror和exit(),无需if判断。
- execl函数:加载一个进程,通过 路径、程序名 来加载。
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
- execlp函数:加载一个进程,借助PATH环境变量
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
- 参数file:要加载的程序的名字,该函数需要配合PATH环境变量共同使用,当PATH中所有目录搜索后没有参数1,则出错返回。
- 参数arg:参数列表(参数列表最后一个需要NULL结尾,哨兵)
- 该函数通常用来调用系统程序,如ls、date、cp、cat等命令。
- 返回值:成功无返回,失败返回-1。
例子:调用系统程序ls。
#include<stdio.h>
#include<unistd.h>
int main()
{
//execlp(const char *file, const char *arg, ...)
execlp("ls","ls","-l","--color=auto",NULL);
//不需要判断返回值
perror("exec err");
return 0;
}
如果使用execl函数,则需要在第一个参数输入要调用程序的绝对路径"/bin/ls"。例如:
#include<stdio.h>
#include<unistd.h>
int main()
{
//execlp(const char *file, const char *arg, ...)
//execlp("ls","ls","-l","--color=auto",NULL);
execl("/bin/ls","ls","-l","--color=auto",NULL);
//不需要判断返回值
perror("exec err");
return 0;
}