创建进程
myproc.c
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("我是父进程\n");
pid_t id = fork();
if(id < 0)
{
printf("创建子进程失败\n");
return 1;
}
else if(id == 0)
{
while(1)
{
printf("我是子进程: pid: %d ,ppid: %d\n",getpid(),getppid());
sleep(1);
}
}
else
{
while(1)
{
printf("我是父进程: pid: %d ,ppid: %d\n",getpid(),getppid());
sleep(1);
}
}
}
子进程0,父进程1,失败-1
查看进程
ps axj | grep myproc
描述,fork创建子进程时,操作系统都做了什么
fork之后子进程和父进程共享全部代码,而不仅仅只有after后的
写时拷贝
在Linux中,fork()系统调用用于创建一个新的进程,新进程是原始进程(父进程)的副本。在fork()调用之后,父进程和子进程共享相同的内存映像,这包括代码段、数据段和堆栈。
在fork()调用之后,父进程和子进程之间使用写时拷贝(Copy-on-Write,COW)技术来减少内存开销。具体来说,当父进程或子进程尝试修改共享的内存页时,操作系统会为修改后的内存页创建一个新的副本,并使父进程和子进程指向各自的副本。
下面是一个示例,演示了父子进程的写时拷贝:
#include <iostream>
#include <unistd.h>
int main() {
int data = 100;
pid_t pid = fork();
if (pid == -1) {
std::cerr << "fork() failed" << std::endl;
return 1;
} else if (pid == 0) {
// 子进程
std::cout << "Child process: data = " << data << std::endl;
data = 200;
std::cout << "Child process: modified data = " << data << std::endl;
} else {
// 父进程
std::cout << "Parent process: data = " << data << std::endl;
data = 300;
std::cout << "Parent process: modified data = " << data << std::endl;
}
return 0;
}
在上述代码中,我们首先定义了一个整数变量data
,并初始化为100。然后,我们调用fork()
系统调用创建一个新的进程。
在子进程中,我们输出data
的值,然后将其修改为200,并再次输出修改后的值。
在父进程中,我们也输出data
的值,然后将其修改为300,并再次输出修改后的值。
运行上述代码,可能会得到如下输出:
Parent process: data = 100
Parent process: modified data = 300
Child process: data = 100
Child process: modified data = 200
可以看到,父子进程共享相同的data
变量,但在修改时会进行写时拷贝,使得父进程和子进程拥有各自的副本。因此,父进程和子进程对data
变量的修改互不影响。
延时申请技术
创建子进程,不需要将不会被访问的,或者只会读取的数据拷贝一份将来会被父进程或者子进程写入的数据才会拷贝但是一般而言os无法提前知道哪些空间可能会被写入,即使拷贝也不知拷贝时间
==所以os使用写时拷贝技术将父子进程的数据进行分离 ==
cpu怎么知道要执行什么指令||子进程为什么从after后执行
进程终止
-
操作系统所作:
操作系统释放进程申请相关的内核数据结构和对应的数据和代码本质就是释放系统资源 -
进程终止的常见方式:
a. 代码跑完,结果正确
b.代码跑完,结果不正确 (main函数返回值的意义?return0 ?)
c.代码没有跑完,程序崩溃了(信号部分)
- 用代码如何终止一个进程
main函数的return语句就是用来终止进程的! return+退出码
exit在代码的任何地方调用,都表示直接终止进程
exit在退出时会将数据刷新到缓冲区 _exit不会
exit || _exit
进程等待
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
wait–基本验证,回收僵尸进程的问题
阻塞式等待
在Linux中,wait()
和waitpid()
是用于进程等待的系统调用。
wait()
系统调用用于让父进程等待其子进程的终止。当父进程调用wait()
时,如果子进程已经终止,则wait()
立即返回,并返回子进程的进程ID。如果子进程还未终止,则父进程会被阻塞,直到子进程终止。
waitpid()
系统调用是wait()
的一个变种,它允许父进程指定要等待的子进程的进程ID。此外,waitpid()
还可以指定一些额外的选项,例如WNOHANG
,使waitpid()
在没有可等待的子进程时立即返回。
下面是一个示例,演示了wait()
和waitpid()
的使用:
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == -1) {
std::cerr << "fork() failed" << std::endl;
return 1;
} else if (pid == 0) {
// 子进程
std::cout << "Child process: PID = " << getpid() << std::endl;
sleep(2); // 子进程休眠2秒
std::cout << "Child process: exiting" << std::endl;
return 0;
} else {
// 父进程
std::cout << "Parent process: PID = " << getpid() << std::endl;
std::cout << "Parent process: waiting for child process to exit" << std::endl;
// 等待子进程终止
int status;
pid_t terminated_pid = wait(&status);
if (WIFEXITED(status)) {
std::cout << "Parent process: child process " << terminated_pid << " exited normally with status " << WEXITSTATUS(status) << std::endl;
} else if (WIFSIGNALED(status)) {
std::cout << "Parent process: child process " << terminated_pid << " exited due to signal " << WTERMSIG(status) << std::endl;
}
}
return 0;
}
在上述代码中,我们使用fork()
创建了一个子进程。在子进程中,我们输出子进程的进程ID,然后休眠2秒钟,最后返回0。
在父进程中,我们输出父进程的进程ID,并使用wait()
等待子进程终止。当子进程终止后,wait()
返回子进程的进程ID,并将子进程的状态存储在status
变量中。我们使用WIFEXITED()
和WEXITSTATUS()
宏来检查子进程是否正常终止,并获取子进程的退出状态。
运行上述代码,可能会得到如下输出:
Parent process: PID = 1234
Parent process: waiting for child process to exit
Child process: PID = 1235
Child process: exiting
Parent process: child process 1235 exited normally with status 0
可以看到,父进程调用wait()
等待子进程终止,并成功获取到子进程的退出状态。
在上述代码中,status
是一个整数变量,用于存储子进程的终止状态。在wait()
或waitpid()
返回时,可以通过检查status
来获取子进程的退出状态。
status
的类型是int
,但它实际上是一个位字段,可以通过一些宏来解析它的值。下面是一些常用的宏:
WIFEXITED(status)
:如果子进程正常终止,则返回真。WEXITSTATUS(status)
:如果WIFEXITED()
为真,则返回子进程的退出状态。WIFSIGNALED(status)
:如果子进程因为信号而终止,则返回真。WTERMSIG(status)
:如果WIFSIGNALED()
为真,则返回导致子进程终止的信号编号。
这些宏可以帮助我们解析status
变量,以确定子进程的终止状态。
在上述示例代码中,我们使用了WIFEXITED()
和WEXITSTATUS()
宏来检查子进程是否正常终止,并获取子进程的退出状态。如果子进程正常终止,WEXITSTATUS()
将返回子进程的退出状态。
如果子进程因为信号而终止,我们可以使用WIFSIGNALED()
和WTERMSIG()
宏来获取导致子进程终止的信号编号。
请注意,status
中的位字段是由操作系统设置的,因此可以使用这些宏来解析status
的值。
waitpid–获取子进程退出结果的问题
status不是按照整数来体现的