【Linux初阶】fork进程创建 & 进程终止 & 进程等待

这篇具有很好参考价值的文章主要介绍了【Linux初阶】fork进程创建 & 进程终止 & 进程等待。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 🌟hello,各位读者大大们你们好呀🌟

🍭🍭系列专栏:【Linux初阶】

✒️✒️本篇内容:fork进程创建,理解fork返回值和常规用法,进程终止(退出码、退出场景、退出方法、exit),进程等待(wait、waitpid),阻塞等待和非阻塞等待

🚢🚢作者简介:本科在读,计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-

目录

一、进程创建

1.fork函数初识

2.fork返回值

(1)如何理解 fork函数有两个返回值

(2)如何理解 fork返回后,给父进程返回子进程的 pid,给子进程返回 0?

(3)如何理解同一个 id值,会返回两个不同的值,让 if 和 else if 同时执行

(4)理解写时拷贝

3.fork常规用法

4.fork调用失败的原因

二、进程终止

1.进程退出码

2.进程退出场景

3.进程常见退出方法

4.exit函数

5._exit函数

6.return

三.进程等待

1.wait方法

2.waitpid方法

3.获取子进程status

4.进程等待总结

四、再谈进程退出

五、阻塞等待 vs 非阻塞等待

1.阻塞等待应用示例 

2.非阻塞等待应用示例


一、进程创建

1.fork函数初识

在linux中fork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>
pid_t fork(void);
返回值:子进程中返回0,父进程返回子进程id,出错返回-1

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度

如下图所示,调用fork后,将生成一个新的进程

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

 代码示例如下

int main(void)
{
	pid_t pid;
	printf("Before: pid is %d\n", getpid());
	if ((pid = fork()) == -1)perror("fork()"), exit(1);
	printf("After:pid is %d, fork return %d\n", getpid(), pid);
	sleep(1);
	return 0;
}

运行结果:
[root@localhost linux]# . / a.out
Before : pid is 43676
After : pid is 43676, fork return 43677
After : pid is 43677, fork return 0

这里看到了三行运行结果,一行before,两行after。进程43676先打印before消息,然后它又打印after。另一个after消息是43677打印的。注意到进程43677没有打印before,为什么呢?如下图所示

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

所以, fork之前父进程独立执行,fork之后,父子两个执行流分别执行
 

我们可以看到上述代码中并没有对父子进程进行条件限制,那么在程序运行起来时,在 fork之后,会先执行父进程还是子进程呢?实际上,fork之后,谁先执行完全由调度器决定。 

2.fork返回值

(1)如何理解 fork函数有两个返回值

首先,我们必须要知道 fork函数是操作系统为我们提供的,也就是说,fork操作是在操作系统内实现的

接下来,我们一起来看下 fork函数内部的结构,然后思考一个问题:在代码在 return之前,内部的核心代码实现完了吗?

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

答案是,实现完了!也就是说,子进程早在 return前就创建好了,并且可能已经在 OS的运行队列中,准备被调度了。对应的,当代码运行到 return时,会有父进程、子进程两个进程各自执行return

(2)如何理解 fork返回后,给父进程返回子进程的 pid,给子进程返回 0?

因为一个父亲的孩子可以有很多个,可是每个孩子都只有一个父亲。也就是说,孩子找父亲是具有唯一性的。以此类推,子进程 fork之后,不需要父进程的 id值,因为父进程具有唯一性。而父进程 fork之后需要对应子进程的 id,因为该父进程可能不止一个子进程,它需要对应的子进程 id做标识

(3)如何理解同一个 id值,会返回两个不同的值,让 if 和 else if 同时执行

返回的本质:就是写入。我们不知道父子进程谁先返回,谁先返回,谁就先写入 id值。由于进程具有独立性,进程在执行 fork相应代码时,会在操作系统内部进行写时拷贝,使 fork对应的进程可以返回两个不同的值,再让对应的父子进程根据自己返回的 id,去执行 if 或 else if 中的代码内容。

(4)理解写时拷贝

通常情况下,父子代码共享,父子进程在不写入(不修改共享部分的数据)时,对应的数据也是共享的。当任意一方试图写入,操作系统便会以写时拷贝的方式,给需要修改的一方在物理内存中开辟一块新空间,将原来的数据拷贝到新空间中,再对新空间中的数据做修改。具体见下图: 

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

———— 我是一条知识分割线 ————

3.fork常规用法

  • 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
  • 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

4.fork调用失败的原因

  • 系统中有太多的进程
  • 实际用户的进程数超过了限制(一个用户可以创建的进程是有限制的)

二、进程终止

1.进程退出码

这里给大家讲解一下进程退出码,我们知道写代码是为了完成某件事情,那我们如何知道这件事完成的怎么样呢?我们可以通过进程退出码来了解。

进程在退出时,会有对应的退出码,标定进程执行的结果是否正确

退出码的意义:0:success,!0:标识失败。 !0具体是几,标识不同的错误 -- 数字对人不友好,对计算机友好。

可以通过 echo $? 查看进程退出码

./mytest    #运行可执行程序mytest
echo $?    #永远记录了最近一个进程在命令行中执行完毕时对应的退出码(main->return ?;),这里的?为一个变量

———— 我是一条知识分割线 ————

一般而言,退出码,都必须有对应的文字描述,

  1. 可以自定义;
  2. 可以使用系统的映射关系(不太频繁)。

补充:在循环内定义变量,如果Linux系统版本比较低,需要在 makefile文件的依赖生成关系的行末加 -std=c99

strerror函数展现所有退出码 - 查看系统不同数字的映射关系

#include<string.h>

int main()
{
    for (int i = 0; i < 200; i++)
    {
        printf("%d: %s\n", i, strerror(i));
    }

    return 0;
}

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

2.进程退出场景

  • 代码运行完毕,结果正确,return 0;
  • 代码运行完毕,结果不正确,return !0;
  • 代码异常终止,退出码无意义。

3.进程常见退出方法

正常终止(可以通过 echo $? 查看进程退出码):

  • 1. 从main函数return返回;
  • 2. 任意地方调用exit(code);
  • 3. _exit。

异常退出:

  • ctrl + c,信号终止

exit - 库函数的一种,作用为终止一个进程的函数(头文件 #include<stdlib.h>),在调用 exit时,进程就终止退出了,代码不会继续向下执行。

_exit - 系统调用的一种,作用为终止一个进程的函数(头文件 #include<unistd.h>),在调用 _exit时,进程就终止退出了,代码不会继续向下执行。

我们尝试在Linux中编译下面的代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
	printf("hello");
	exit(0);
}
运行结果:
[root@localhost linux] # . / a.out
hello[root@localhost linux]#

int main()
{
	printf("hello");
	_exit(0);
}
运行结果:
[root@localhost linux] # . / a.out
[root@localhost linux]#

运行后我们会发现一个现象,exit(0)代码运行需要几秒后才能把 hello打印出来,这是因为数据在缓冲区中,进程退出后才能在缓冲区刷到我们对的屏幕上。但是当我们使用 _exit(0)时,频幕上不会有任何信息打印,也就是说,_exit()退出后不会刷新缓冲区。

总结:exit 终止进程,主动刷新缓冲区;_exit 终止进程,不会刷新缓冲区缓冲区存在于用户层

4.exit函数

#include <unistd.h>
void exit(int status);

参数:status 定义了进程的终止状态,父进程通过wait来获取该值,后面第三节会讲

说明:虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值是255。

exit最后也会调用 _exit, 但在调用 _exit之前,还做了其他工作:

  1. 执行用户通过 atexit或on_exit定义的清理函数;
  2. 关闭所有打开的流,所有的缓存数据均被写入;
  3. 调用_exit。

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

5._exit函数

#include <unistd.h>
void _exit(int status);
参数:status 定义了进程的终止状态,父进程通过wait来获取该值

6.return

在我们编写 C/C++代码时,通常我们的 main函数结尾都会带有一段 return 0 的代码,不知道朋友们有没有想过这里的 return 0 的作用是什么呢?

结合我们上面的讲解,我们不难理解其实这里的 0就是进程退出码,如果我们不关心进程退出码,return 0就可以了。如果未来我们是要关心进程退出码的时候,要返回特定的数据表明不同的错误。


三.进程等待

我们之前就学习过僵尸进程的相关知识,我们知道在一个在进程退出的时候,需要退出的相关信息返回给父进程。那么假如子进程处于僵尸状态无法退出返回相关信息怎么办呢?这里就需要用到我们进程等待的知识了。我们可以通过进程等待的方式解决僵尸进程

进程等待的必要性

  • 之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。
  • 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
  • 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

1.wait方法

#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int* status);

返回值:
成功返回被等待进程pid,失败返回 -1。
参数:
输出型参数,获取子进程退出状态, 不关心则可以设置成为NULL

常见使用方法

pid_t ret = wait(NULL);

代码示例

#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>

int main()
{
    pid_t id = fork();
    if (id == 0)
    {
        //子进程
        int cnt = 10;
        while (cnt)
        {
            printf("我是子进程: %d, 父进程: %d, cnt: %d\n", getpid(), getppid(), cnt--);
            sleep(1);
        }

        exit(0); //进程退出
    }

    // 父进程
    sleep(15);
    pid_t ret = wait(NULL);
    if (id > 0)
    {
        printf("wait success: %d", ret);
    }

    sleep(5);
}

 【Linux初阶】fork进程创建 & 进程终止 & 进程等待

注意:这里我们可以把 wait理解为一个函数调用,目的是返回一个值(子进程的返回信息),给父进程

2.waitpid方法

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
    当正常返回的时候,waitpid返回收集到的子进程的进程ID;
    如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
    如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
     pid:
         Pid=-1,等待任一个子进程。与wait等效。
         Pid>0.等待其进程ID与pid相等的子进程。
     status:
         WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
         WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
     options:
         WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

常见使用方法

int status = 0; // 不是被整体使用的,有自己的位图结构
pid_t ret = waitpid(id, &status, 0); //wait子进程

补充: 

  • 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。
  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。
  • 如果不存在该子进程,则立即出错返回。

3.获取子进程status

  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

退出状态中保存的是进程的退出码(判断运行结果是否正确),终止信号可以知道进程是否正常退出/结束。终止信号为0代表正常结束,只有终止信号为0才能去看退出状态,退出状态为0则代表运行结果正确,其他数字则代表其他不同的运行情况

  • 代码示例1(代码正常结束、运行正确,返回退出/终止状态信号0、exit的退出码10,这里的10是我自己自定义的)
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>

int main()
{
    pid_t id = fork();
    if (id == 0)
    {
        //子进程
        int cnt = 5;
        while (cnt)
        {
            printf("我是子进程: %d, 父进程: %d, cnt: %d\n", getpid(), getppid(), cnt--);
            sleep(1);
        }

        exit(10); //进程退出
    }

    // 父进程
    int status = 0; // 不是被整体使用的,有自己的位图结构
    pid_t ret = waitpid(id, &status, 0);
    if (id > 0)
    {
        printf("wait success: %d, sig number: %d, child exit code: %d\n", ret, (status & 0x7F), (status >> 8) & 0xFF);
    }

    sleep(5);
}

信号编号(终止信号)为低七位,我们可以通过 status & 0x7F获得;

退出码(在退出状态中)在次低八位,我们可以通过 (status>>8)&0xFF获得;

在程序正常运行的情况下,使用 exit返回,终止信号为0,退出码为 exit(?) 的 ?值。

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

  •  代码示例2(野指针,返回退出/终止状态信号11、exit的退出码0,这里的0是系统自动返回的)
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>

int main()
{
    pid_t id = fork();
    if (id == 0)
    {
        //子进程
        int cnt = 5;
        while (cnt)
        {
            printf("我是子进程: %d, 父进程: %d, cnt: %d\n", getpid(), getppid(), cnt--);
            sleep(1);
            int* p = NULL;//野指针
            *p = 100;
        }

        exit(10); //进程退出
    }

    // 父进程
    int status = 0; // 不是被整体使用的,有自己的位图结构
    pid_t ret = waitpid(id, &status, 0);
    if (id > 0)
    {
        printf("wait success: %d, sig number: %d, child exit code: %d\n", ret, (status & 0x7F), (status >> 8) & 0xFF);
    }

    sleep(5);
}

 在程序非正常运行时,使用 exit返回,终止信号为对应的信号值,退出码为0。终止信号不为0,代表非正常退出。

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

 11)SIGSEGV - 段错误,出现野指针后会有此类错误

  • 代码示例3(借助status值,检验子进程是否正常退出)

status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
 WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码) 

int main()
{
    pid_t id = fork();
    assert(id != -1);
    if (id == 0)
    {
        //child
        int cnt = 10;
        while (cnt)
        {
            printf("child running, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt--);
            sleep(1);
            //    int *p = 0;
            //    *p = 100; //野指针问题
        }

        exit(10);
    }

    int status = 0;
    // 1. 让OS释放子进程的僵尸状态
    // 2. 获取子进程的退出结果
    // 在等待期间,子进程没有退出的时候,父进程只能阻塞等待
    int ret = waitpid(id, &status, 0);
    if (ret > 0)
    {
        // 是否正常退出
        if (WIFEXITED(status))
        {
            // 判断子进程运行结果是否ok
            printf("exit code: %d\n", WEXITSTATUS(status));
        }
        else {
            //TODO
            printf("child exit not normal!\n");
        }
        //printf("wait success, exit code: %d, sig: %d\n", (status>>8)&0xFF, status & 0x7F);
    }

    return 0;
}

4.进程等待总结

wait和waitpid中的status参数,可以在子进程处于阻塞状态(运行完但是运行信息还没有被父进程回收)时,检测子进程的退出信息,将子进程存储于 PCB中的退出信息拿回到父进程中。这个操作由造作系统完成。


四、再谈进程退出

  1. 进程退出会变成僵尸,同时该进程也会把自己对应的退出码写入到自己的 task_struct中;
  2. wait/waitpid 是一个系统调用,也就是说,它们是由 OS完成的,OS有能力去读取子进程的task_struct;
  3. 所以,父进程获取到的子进程退出信息,是从退出子进程的 task_struct中获取到的

下面是 Linux源码 task_struct中的部分内容

【Linux初阶】fork进程创建 & 进程终止 & 进程等待


五、阻塞等待 vs 非阻塞等待

  • 阻塞等待:持续检测子进程状态,不进行其他工作;
  • 非阻塞等待:间隔性检测子进程状态,如果没有就绪,直接返回。在子进程没有退出的前提下,每一次的退出都是以此非阻塞等待;
  • 非阻塞等待下,获取子进程退出状态成功和不成功,对应的返回值不同成功返回一个大于0的值,不成功则返回0
  • 多次非阻塞等待称为轮询

非阻塞等待有什么好处?

不会让等待占用父进程所有的精力,可以在轮询期间,干干别的!具体是什么意思呢?简单来说,就是父进程每隔一段时间去查看等待是否成功,在此期间,父进程可以进行别的工作

1.阻塞等待应用示例 

int main()
{
	pid_t pid;
	pid = fork();
	if (pid < 0) {
		printf("%s fork error\n", __FUNCTION__);
		return 1;
	}
	else if (pid == 0) 
	{ 
		//child
		printf("child is run, pid is : %d\n", getpid());
		sleep(5);
		exit(257);
	}
	else 
	{
		int status = 0;
		pid_t ret = waitpid(-1, &status, 0);//阻塞式等待,等待5S
		printf("this is test for wait\n");
		if (WIFEXITED(status) && ret == pid) {
			printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));
		}
		else {
			printf("wait child failed, return.\n");
			return 1;
		}
	}
	return 0;
}

运行结果:
[root@localhost linux] # . / a.out
child is run, pid is : 45110
this is test for wait
wait child 5s success, child return code is : 1.

 可以观察到,进程在打印 child is run, pid is : 45110  5s之后才打印后续的代码

2.非阻塞等待应用示例 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

#define NUM 10

typedef void (*func_t)(); //函数指针

func_t handlerTask[NUM]; //函数指针数组

//样例任务
void task1()
{
    printf("handler task1\n");
}
void task2()
{
    printf("handler task1\n");
}
void task3()
{
    printf("handler task1\n");
}

void loadTask()
{
    memset(handlerTask, 0, sizeof(handlerTask));//将数组handlerTask初始化为0,需要#include <string.h>
    handlerTask[0] = task1;//将3个函数指针对应3个任务
    handlerTask[1] = task1;
    handlerTask[2] = task1;
}

void addtask()
{}

int main()
{
    pid_t id = fork();
    assert(id != -1);
    if (id == 0)
    {
        //child
        int cnt = 10;
        while (cnt)
        {
            printf("child running, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt--);
            sleep(1);
        }

        exit(10);
    }

    loadTask(); //给父进程装载一批任务
    // parent
    int status = 0;
    while (1)
    {
        pid_t ret = waitpid(id, &status, WNOHANG); //WNOHANG: 非阻塞-> 子进程没有退出, 父进程检测时候,立即返回
        if (ret == 0)
        {
            // waitpid调用成功 && 子进程没退出
            //子进程没有退出,我的waitpid没有等待失败,仅仅是监测到了子进程没退出.
            printf("wait done, but child is running...., parent running other things\n");
            for (int i = 0; handlerTask[i] != NULL; i++)
            {
                handlerTask[i](); //采用回调的方式,执行我们想让父进程在空闲的时候做的事情
            }
        }
        else if (ret > 0)
        {
            // 1.waitpid调用成功 && 子进程退出了
            printf("wait success, exit code: %d, sig: %d\n", (status >> 8) & 0xFF, status & 0x7F);
            break;
        }
        else
        {
            // waitpid调用失败
            printf("waitpid call failed\n");
            //    break;
        }
        sleep(1);
    }

    return 0;
}

【Linux初阶】fork进程创建 & 进程终止 & 进程等待

可以观察到,在子进程还没有退出的时候,父进程完成了其他的工作 


 🌹🌹 Linux下的fork进程创建 & 进程终止 & 进程等待 的知识大概就讲到这里啦,博主后续会继续更新更多Linux操作系统的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪 文章来源地址https://www.toymoban.com/news/detail-462538.html

到了这里,关于【Linux初阶】fork进程创建 & 进程终止 & 进程等待的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…

    柴犬: 你好啊,屏幕前的大帅哥or大美女,和我一起享受美好的今天叭😃😃😃 1. 在调用fork函数之后, 当执行的程序代码转移到内核中的fork代码后 ,内核需要分配 新的内存块 和 内核数据结构 给子进程, 内核数据结构包括PCB、mm_struct和页表,然后构建起映射关系 ,同时

    2024年01月16日
    浏览(58)
  • 【探索Linux】—— 强大的命令行工具 P.10(进程的控制——创建、终止、等待、程序替换)

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了关于进程的地址空间,今

    2024年02月08日
    浏览(53)
  • 【Linux初阶】进程的相关概念 | 进程管理 & 查看进程 & 获取进程标识符 & fork进程创建

     🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:进程的概念,进程管理初识(描述、管理进程),查看进程的基础方法,获取进程标识符(pid、ppid),fork进程创建(分流应用) 🚢🚢作者简介:计算机海洋的新进船长一枚,请多多

    2023年04月27日
    浏览(44)
  • 【Linux】详解进程终止&&进程等待

             页表中不仅仅只有虚拟地址到物理地址的映射,还包括了很多选项,其中就包括了映射条目的权限。当我们进程的代码和数据加载到内存并和进程地址空间建立映射关系时,如果数据的内容不允许被修改(比如说常量字符串),对应数据在页表中的映射条目的权

    2024年04月14日
    浏览(63)
  • fork函数如何创建进程,exit/_exit函数如何使进程终止的详细分析与代码实现

    🎊【进程通信与并发】专题正在持续更新中,进程,线程,IPC,线程池等的创建原理与运用✨,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  ​​​​​​并发与进程通信 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人主页 - 勾栏听曲

    2024年02月05日
    浏览(46)
  • 零基础Linux_10(进程)进程终止(main函数的返回值)+进程等待

    目录 1. 进程终止 1.1 main函数的返回值 1.2 进程退出码和错误码 1.3 进程终止的常见方法 2. 进程等待 2.1 进程等待的原因 2.2 wait 函数 2.3 waitpid 函数 2.4 int* status参数 2.5 int options非阻塞等待 本篇完。 进程终止指的就是程序执行结束了,进程终止退出的场景有三种: 代码运行

    2024年02月07日
    浏览(43)
  • Linux之进程控制&&进程终止&&进程等待&&进程的程序替换&&替换函数&&实现简易shell

    1.1 fork的使用 我们可以使用man指令来查看一下 子进程会复制父进程的PCB,之间代码共享,数据独有,拥有各自的进程虚拟地址空间。 这里就有一个代码共享,并且子进程是拷贝了父进程的PCB,虽然他们各自拥有自己的进程虚拟地址空间,数据是拷贝过来的,通过页表映射到

    2024年04月17日
    浏览(57)
  • 【Linux进程】查看进程&&fork创建进程

    目录 前言  1. 查看进程  2. 通过系统调用创建进程-fork初识 总结          你有没有想过在使用Linux操作系统时,后台运行的程序是如何管理的?在Linux中,进程是一个非常重要的概念。本文将介绍如何查看当前运行的进程,并且讨论如何使用fork创建新的进程。通过了解这些

    2024年01月22日
    浏览(54)
  • Linux——进程创建与进程终止

    📘北尘_ :个人主页 🌎个人专栏 :《Linux操作系统》《经典算法试题 》《C++》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 #include unistd.h pid_t fork(void); 返

    2024年02月04日
    浏览(50)
  • Linux:创建进程 -- fork,到底是什么?

     相信大家在初学进程时,对fork函数创建进程一定会有很多的困惑,比如: 1.fork做了什么事情??  2.为什么fork函数会有两个返回值? 3.为什么fork的两个返回值,会给父进程谅回子进程pid,给子进程返回0? 4.fork之后:父子进程谁先运行?? 5.如何理解同一个变量,会有不同的值?? 本

    2024年02月05日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包