进程(Process)和线程(Thread)是操作系统中管理和执行任务的两个基本概念。
进程:
进程(Process):动态的,会对一些内存进行调用;进程是资源管理的最小单位。
- 进程是操作系统中的一个独立执行单位,可以看作是程序的运行实例。
- 每个进程都有独立的内存空间、代码、数据和其他资源。
- 进程之间相互独立,通过操作系统提供的进程间通信机制(如管道、信号等)进行通信。
- 进程具有自己的进程控制块(Process Control Block,PCB),用于存储和管理进程的信息,如进程状态、程序计数器、内存分配等。
线程:
线程(Thread):线程就是资源调度的最小单位。
- 线程是进程中的一个执行单元,是进程中的一个执行流。
- 一个进程可以包含多个线程,多个线程共享进程的资源和上下文。
- 线程可以看作是进程中的一个子任务,它们共享同一份数据空间。
- 线程之间的切换比进程的切换开销要小,线程间的通信相对简单。
创建新的进程:
功能 |
创建一个新的进程 |
|
头文件 |
#include < unistd.h> |
|
原型 |
pid_t fork(void); |
|
返回值 |
成功 |
0 或者大于 0 的正整数 |
失败 |
- 1 |
|
备注 |
该函数执行成功之后,将会产生一个新的子进程,在新的子进程中其返 回值为 0 ,在原来的父进程中其返回值为大于 0 的正整数,该正整数就 是子进程的 PID |
在运行过程中,父进程运行打印结束后子进程才打印,父进程与子进程的资源是相互独立的并不是共享的同一块。当父进程退出或异常终止后,仍然在操作系统中运行的子进程,称之为“孤儿进程”,操作系统会接管这些孤儿进程——统一由“2006”进行孤儿管理。
查看所以进行信号:kill -l
要防止出现孤儿进程,可以采取以下措施:
-
等待子进程结束:在父进程中使用
wait()
或waitpid()
系统调用等待子进程结束,这样可以确保父进程在子进程退出之前不会退出。 -
使用信号处理程序:在父进程中注册一个信号处理程序,监听子进程退出的信号(例如
SIGCHLD
)。当接收到该信号时,父进程可以执行相应的操作,比如调用wait()
或waitpid()
来回收子进程资源。 -
设置忽略信号:在父进程中通过调用
signal()
函数,将SIGCHLD
信号设置为忽略。这样操作系统会自动回收子进程的资源,避免产生孤儿进程。 -
进程组设置:将子进程加入父进程所在的进程组。这样,在父进程退出时,整个进程组都会收到一个终止信号,子进程会随之终止。
-
使用守护进程:守护进程是一种在后台运行的进程,它通常作为系统服务存在。守护进程在启动时会创建一个孤儿进程,并且不会退出,因此不会产生孤儿进程。
需要注意的是,这些措施并不能完全消除孤儿进程的出现,但能够有效地减少其发生的概率,即使子进程成为了孤儿进程,它仍然可以继续正常运行,直到自己退出或者被终止。而且,如果孤儿进程创建了自己的子进程,那么这些子进程仍然属于孤儿进程的子进程,直到它们退出或者在操作系统中接收到新的父进程。
退出本进程:
功能 |
退出本进程 |
|
头文件 |
#include <unistd.h> #include <stdlib.h> |
|
原型 |
void _exit(int status); void exit(int status); |
|
参数 |
status |
子进程的退出值 |
返回值 |
不返回 |
|
备注 |
1,如果子进程正常退出,则 status 一般为 0。 2,如果子进程异常退出,则 statuc 一般为非 0。 3,exit( )退出时,会自动冲洗 (flush) 标准 IO 总残留的数据到内核,如果进程注册 了“退出处理函数”还会自动执行这些函数。而_exit( )会直接退出。 |
- exit()是C标准库函数,检查有没有注册退出处理函数,检查IO缓冲区是否有数据,有数据就打印输出,然后退出,适合正常终止进程。
- _exit()是系统调用,立即终止进程,无需进行任何清理操作,适合不需要执行其他操作的终止情况。
注册退出处理函数:atexit(),当程序exit退出的时候,如果注册了退出处理函数就会执行。使用的是顺序栈的入栈和出栈的特性。atexit()函数用于向进程注册一个函数,当进程正常终止时,这个函数将会被自动调用。这个函数可以注册多个,它们将按照注册的顺序逆序执行,调用是按照注册的逆序执行的,即最后注册的函数最先执行。这个机制通常用于执行一些清理操作,例如关闭文件、释放资源等。
在io文件中printf()函数在输出时不加换行'\n',就会将数据写入到IO缓冲区中,直到满一行再输出。
进程中加载新的程序文件或者脚本,覆盖原有代码,重新运行:
exec函数簇,主要是用来覆盖子进程复制的代码,执行自己想执行的内容。
功能 |
在进程中加载新的程序文件或者脚本,覆盖原有代码,重新运行 |
|
头文件 |
#include <unistd.h> |
|
原型 |
int execl(const char *path, const char *arg, ...);< |