目录
进程
系统创建进程时,会给进程一个虚拟的地址空间,让进程存储自己运行时需要的资源。同时,进程还可以创建线程,以执行自己的程序。
子进程的创建
子进程的创建采用fork(2)函数,使用时要包含unistd.h头文件:
pid_t fork(void);
这个函数将会通过复制调用进程,创建一个新进程。调用进程被称为父进程,被创建的新进程叫子进程。子进程与父进程运行在不同的地址空间。在刚创建时,两个进程的地址空间的内容一样,且互不影响。除了以下几点,子进程将会精确复制父进程:
-
子进程有自己的唯一进程ID,这个PID与任何现有进程组的ID都不匹配。
-
子进程的父进程ID与父进程的进程ID相同。
-
子进程不继承其父进程的内存锁。
-
子进程的进程资源利用率和CPU时间计数器被重置为零。
-
子进程的待处理信号集初始为空。
-
子进程不继承其父进程的信号量调整。
-
子进程不继承其父进程的进程相关记录锁。
-
子进程不继承其父进程的定时器。
-
子进程不继承其父进程的未完成的异步I/O操作,也不继承其父进程的任何异步I/O上下文。
这里面可能有些名词不知道,不过没有关系,这些都是linux的底层操作。
这个函数会创建一个子进程,因此,剩下的程序会在子进程和父进程中同时执行。在父进程中,它会返回子进程的进程ID;在子进程中,它会返回0.
如果创建出错,它会返回-1,并将errno的值设为对应的错误值。
以下程序演示了在父进程中创建子进程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void){
int test = 0;
int *p = (int *)malloc(sizeof(int));
*p = 0;
// 创建一个子进程
int pid = fork();
if(pid == -1){
printf("创建失败\n");
goto ERROR;
}
// 判断当前进程是子进程或父进程
if(pid == 0){
// 演示子进程和父进程的地址空间相互独立
printf("这是子进程\n");
printf("子进程没有改变test的值\n");
printf("test = %d\n", test);
printf("*p = %d\n", *p);
}else{
printf("这是父进程\n");
test = 5;
printf("父进程已经将test变量改成了5\n");
printf("test = %d\n", test);
*p = 4;
printf("父进程已经将堆区某地址的值设为了4,这个地址的指针是p\n");
printf("*p = %d\n", *p);
}
// 演示子进程与父进程执行相同的代码
printf("这可能是子进程或父进程\n");
return 0;
ERROR:
return -1;
}
以下是代码的流程:
-
初始化一个整数
test
为 0,并动态分配地址给一个整数指针p
。 -
创建一个子进程。
-
检查
fork()
的返回值以确定当前进程是子进程还是父进程。-
如果
fork()
返回 -1,表示进程创建失败,打印 "创建失败" 并跳到错误处理部分。 -
如果返回值是 0,表示当前是子进程,打印 "这是子进程",并输出
test
和*p
的值。 -
如果返回值是正数(通常是父进程的进程ID),表示当前是父进程。
- 打印 "这是父进程"。
- 将
test
变量设置为 5。 - 输出
test
的新值。 - 将指针
p
所指向的地址设置为 4。 - 输出
*p
的新值。
-
-
最后,无论当前是子进程还是父进程,都会打印 "这可能是子进程或父进程"。
-
如果出现错误,则进入错误处理部分,main函数返回 -1。
运行结果:
这是父进程
父进程已经将test变量改成了5
test = 5
父进程已经将堆区某地址的值设为了4,这个地址的指针是p
*p = 4
这可能是子进程或父进程
这是子进程
子进程没有改变test的值
test = 0
*p = 0
这可能是子进程或父进程
可以看到,父进程与子进程会运行同一段程序,并且地址空间相互独立。
进程信号
一个进程可以向另一个进程发送信号,或接收其他进程的信号。
多进程操作可以创建多个进程,每个进程之间可以相互发送和接收信号,因此,有必要讲一下进程的信号。
当接收到信号后,系统会进行一些默认操作。用户也可以自定义操作。
系统的默认操作分为以下几个:
终止操作 | 终止进程 |
忽略操作 | 忽略信号 |
核心转储 | 终止进程并核心转储,即存储一个地址空间快照以便调试 |
停止操作 | 停止进程 |
继续操作 | 继续运行一个停止的进程 |
Linux提供了如下标准信号:
信号 | 宏定义的整数值 | 默认操作 | 解释 |
---|---|---|---|
SIGHUP | 1 | 终止 | 控制终端挂起或控制进程意外终止 |
SIGINT | 2 | 终止 | 从键盘中终止(通常按下Crtl+C) |
SIGQUIT | 3 | 核心转储 | 从键盘中退出(通常按下Ctrl+\) |
SIGILL | 4 | 核心转储 | 遇到非法命令 |
SIGABRT | 6 | 核心转储 | 从abort(3)函数中发送了终止信号 |
SIGFPE | 8 | 核心转储 | 浮点数异常 |
SIGKILL |