进程的创建、多任务及退出

一、创建进程

1、并发与并行

为了提高计算机执行任务的效率,一般采用的解决方案就是能够让多个任务同时进行,可以使用 并发
并行两种方式
并行 : cpu 多核的支持下,实现物理上的同时执行
并发 : 在有限的 cpu 核芯的情况下 , 利用快速交替 ( 时间片轮转 ) 执行来达到宏观上的同时执行
总结:并行是基于硬件完成,而并发则可以使用软件算法来完成,可以创建多个进程并发执行来完成任务

二、进程创建

1、fork() 函数

通过调用 fork() 函数,则会产生一个新的进程。调用 fork() 函数的进程叫做 父进程 ,产生的新进程则为 进程
函数头文件
#include <sys/types.h>
#include <unistd.h>
函数原型
pid_t fork(void);
函数功能
创建一个子进程
函数返回值
成功 : 返回给父进程是子进程的 pid, 返回给子进程的是 0
失败 : 返回 -1, 并设置 errno
代码
// 创建一个子进程,并打印 Hello fork
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid==-1)
    {
        perror("fork");
        return -1;
    }
    printf("Hello fork.\n");
    return 0;
}
运行结果
问题 1 :为什么显示两次 "hello fork"
是因为打印语句在两个进程中都运行了
问题 1 :为什么两次显示结果有差异?
如果父进程在子进程打印之前结束,则会回到终端命令后继续执行子进程;如果子进程的
打印语句在父进程结束之前执行,则会在回到终端命令前执行完毕。
代码
// 创建一个子进程,并打印进程的pid
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid==-1)
    {
        perror("fork");
        return -1;
    }
    printf("pid = %d,Hello fork.\n",getpid());
    return 0;
}

结果:

2 、父子进程

通过 fork() 函数创建子进程,有如下特点 :
父子进程并发执行,子进程从 fork() 函数之后开始执行
父子进程的执行顺序由操作系统算法决定的,不是由程序本身决定
子进程会拷贝父进程地址空间的内容,包括缓冲区、文件描述符等
例代码
// 父子进程数据空间拷贝,缓冲区的拷贝
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    // 标准IO
    write(1,"write hello.",12);
    // 文件IO自带缓冲区
    fputs("fputs hello.",stdout); // 注意没有换行符,stdout的缓冲区属于行
    缓冲
    pid_t pid = fork();
    if(pid==-1)
    {
            perror("fork");
            return -1;
    }
    printf("pid = %d,Hello fork.\n",getpid());
    return 0;
}
文件描述符的拷贝
每个进程都会维护一个文件表项,即文件描述符与文件指针的映射表
Linux 内核中有一个 struct file 结构体来管理所有打开的文件
当子进程拷贝了父进程文件描述符后,则会共享文件状态标志与文件偏移量等信息

三、进程多任务

1、父子进程执行不同的任务

使用 fork() 函数之后,会创建子进程, fork() 之后的代码会在父子进程中都执行。
如果父子进程执行相同的任务,则正常执行
如果父子进程执行不同的任务,则需要利用 fork() 函数返回值
例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    printf("multitask.\n");
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
        return -1;
    }
    else if(pid==0)
    {
        printf("child process task.\n");
        exit(EXIT_SUCCESS);
    }
    else
    {
        printf("parent process task.\n");
    }
    printf("parent and child task.\n");
    return 0;
}

2、创建多个进程、

在创建多个进程时 , 最主要的原则是 由父进程统一创建,统一管理,不能进行递归创建
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
        return -1;
    }
    else if(pid==0)
    {
        printf("child process <%d> is running.....\n",getpid());
        sleep(2);
        printf("child process <%d> ready to exit.\n",getpid());
        exit(EXIT_SUCCESS);
    }
    else
    {
    // 父进程中继续创建子进程
    pid = fork();
    if(pid == -1)
    {
        perror("fork");
        return -1;
    }
    else if(pid == 0)
    {
        printf("child process <%d> is
        running.....\n",getpid());
        sleep(4);
        printf("child process <%d> ready to
        exit.\n",getpid());
        exit(EXIT_SUCCESS);
    }
    printf("parent process task.\n");
    }
    printf("parent and child task.\n");
    return 0;
}

四、进程的退出

在进程结束时,需要释放分配给进程的地址空间以及内核中产生的各种数据结构
资源的释放需要通过 exit 函数或者 _exit 函数来完成
在程序结束时,会自动调用 exit 函数

1、exit_exit

exit

函数头文件
#include <stdlib.h>
函数原型
void exit(int status);
函数功能
结束进程,并刷新缓冲区
函数参数
status: 退出状态值
在系统中定义了两个状态值 : EXIT_SUCCESS 正常退出, EXIT_FAILURE 异常退出,具体定义在
stdlib.h
#define EXIT_FAILURE 1 /* Failing exit status. */
#define EXIT_SUCCESS 0 /* Successful exit status. */
代码 1 :创建一个子进程,让子进程延时 2s 后退出
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(pid==0)
    {
    printf("child process <%d> is running.....\n",getpid());
    sleep(2);
    exit(EXIT_SUCCESS);
    printf("child process <%d> ready to exit.\n",getpid());
    }
    else
    {
        sleep(5);
    }
    return 0;
}
代码 2 :说明 exit 函数会刷新缓冲区
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(pid==0)
    {
        printf("child process <%d> is running.....",getpid()); // 注意此处没有换行符
        sleep(2);
        exit(EXIT_SUCCESS);
        printf("child process <%d> ready to exit.\n",getpid());
    }
    else
    {
        sleep(5);
    }
    return 0;
}
备注:发现执行 printf("child process <%d> is running.....",getpid()); 语句时并不是立即打
印,而是会延迟 2s
_exit
_exit 函数与 exit 函数功能相同
函数头文件
#include <unistd.h>
函数原型
void _exit(int status);
函数参数
status: 进程退出的状态值
代码 1: 创建一个子进程,使用 _exit 函数让子进程延时 2s 后退出
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
        else if(pid==0)
    {
        printf("child process <%d> is running.....\n",getpid());
        sleep(2);
        printf("child process <%d> ready to exit.\n",getpid());
        _exit(EXIT_SUCCESS);
    }
    else
    {
        sleep(5);
    }
    return 0;
}
代码 2: 创建一个子进程,使用 _exit 函数让子进程延时 2s 后退出
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
        }
        else if(pid==0)
        {
        // 此条语句没有换行符
        printf("child process <%d> is running.....",getpid());
        sleep(2);
        _exit(EXIT_SUCCESS);
        }
        else
        {
            sleep(5);
        }
        return 0;
    }
1.3 exit _exit 的不同
_exit() 属于 系统调用 ,能够使进程停止运行,并释放空间以及销毁内核中的各种数据结构
exit() 基于 _exit() 函数实现,属于库函数 , 会自动刷新 I/O 缓冲区
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值