进程相关函数

1.fork()

fork函数主要用于在一个进程中创建子进程,目的是为了能够在一个程序里面分别独立执行多个任务,相互之间还没有影响

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:
父进程创建一个子进程
参数:
无
返回值:
成功:
>0   子进程的进程号,标识父进程的代码区
0    标识子进程的代码区
失败:
-1

1.1 实例1:fork的含义

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

int main(int argc, char const *argv[])
{
    //注意:只要执行一次fork,就会在原有的进程基础上创建一个子进程
    //如果不区分父子进程的代码区,后面所有的代码都会执行
    // fork();
    // fork();
    // fork();

    // while(1)
    // {

    // }

    int i;
    for(i = 1; i <= 3; i++)
    {
        fork();
        printf("hello world\n");
        sleep(1);
    }
    
    return 0;
}

1.2 实例2:父子进程区分代码区

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

int main(int argc, char const *argv[])
{
    //如果要使用fork在一个程序里面创建子进程
    //肯定是为了执行不同的任务,所以一般都要区分父子进程的代码区

    //使用fork创建一个子进程
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        return -1;
    }
    else if(pid > 0) //父进程的代码区
    {
        printf("正在执行父进程的代码\n");
    }
    else //子进程的代码区
    {
        printf("正在执行子进程的代码\n");
    }

    //如果区分了父子进程运行的代码,则父进程和子进程都只执行自己的,
    //但是当区分的代码执行完毕后,如果进程没有结束,则会继续向下执行,
    //如果不区分父子的代码区,那么都会执行

    printf("hello world\n");


    return 0;
}

1.3 实例3:父子进程运行顺序问题

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

int main(int argc, char const *argv[])
{
    //进程的调度机制是时间片轮转,上下文切换
    //所以父子进程在执行的时候不是父进程执行完
    //再执行子进程,而是来回交替执行,谁先执行
    //谁后执行是不确定的

    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        return -1;
    }
    else if(pid > 0) //父进程的代码区
    {
        printf("正在执行父进程的代码\n");
        sleep(1);
        printf("父进程父进程父进程\n");
    }
    else //子进程的代码区
    {
        printf("正在执行子进程的代码\n");
        sleep(1);
        printf("子进程子进程子进程\n");
    }

    while(1){}

    return 0;
}

1.4 实例4:父子进程的用户空间资源问题

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

//当父进程执行完fork之后,就会创建一个子进程,
//子进程会将父进程的虚拟内存复制一份作为子进程的空间,
//当复制完毕之后,父进程和子进程的用户空间是独立的,
//所以父进程或者子进程任意对用户空间操作,相互是不会
//有影响的

int a = 100;

int main(int argc, char const *argv[])
{
    int b = 200;
    static int c = 300;

    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        return -1;
    }
    else if(pid > 0) //父进程的代码区
    {
        printf("正在执行父进程的代码\n");
        a = 666;
        b = 777;
        c = 888;
        printf("父进程:a = %d, b = %d, c = %d\n", a, b, c);
        printf("父进程:&a = %p, &b = %p, &c = %p\n", &a, &b, &c);
    }
    else //子进程的代码区
    {
        sleep(1);
        printf("正在执行子进程的代码\n");
        printf("子进程:a = %d, b = %d, c = %d\n", a, b, c);
        printf("子进程:&a = %p, &b = %p, &c = %p\n", &a, &b, &c);
    }

    while(1){}

    return 0;
}

1.5 实例5:父子进程对共享资源操作问题

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
    int fd;
    if((fd = open(argv[1], O_RDWR)) == -1)
    {
        perror("open error");
        return -1;
    }
    
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        return -1;
    }
    else if(pid > 0) //父进程的代码区
    {
        printf("正在执行父进程的代码\n");
        //父进程向文件写入数据
        write(fd, "hello world\n", 12);
        printf("offset = %ld\n", lseek(fd, 0, SEEK_CUR));
    }
    else //子进程的代码区
    {
        sleep(1);
        printf("正在执行子进程的代码\n");
        //子进程从文件中读取数据
        printf("offset = %ld\n", lseek(fd, 0, SEEK_CUR));
        lseek(fd, 0, SEEK_SET);
        char buf[32] = {0};
        read(fd, buf, 32);
        printf("buf = [%s]\n", buf);
    }

    while(1){}

    return 0;
}

2.getpid()/getppid()

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

获取当前进程的进程号
pid_t getpid(void);

获取当前进程的父进程的进程号
pid_t getppid(void);

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

int main(int argc, char const *argv[])
{
    pid_t pid = fork();

    if(pid == -1)
    {
        perror("fork error");
        return -1;
    }
    else if(pid > 0) //父进程
    {
        printf("父进程:pid = %d, ppid = %d\n", getpid(), getppid());
        printf("父进程的子进程的进程号:%d\n", pid);
    }
    else  //子进程
    {
        printf("子进程:pid = %d, ppid = %d\n", getpid(), getppid());
    }

    while(1){}

    return 0;
}

3. exit()/_exit()

#include <stdlib.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
功能:
退出当前进程
参数:
status:
当前进程退出的状态值,
可以返回给父进程(父进程可以通过wait函数获取这个值)
一般不需要将这个值返回给父进程,所以一般设置为0表示成功
退出,非0表示错误退出
返回值:
无

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

void myfun()
{
    printf("nihao beijing");
    
    //return如果放在main函数中执行,可以结束当前进程,
    //但是如果是在子函数中执行,只能退出当前函数
    //return ;

    //exit函数不管在哪执行,都会结束整个进程
    //exit和_exit的区别是
    //exit是库函数,会自动刷新缓冲区
    //_exit是系统调用,不会刷新缓冲区
    exit(0);
    //_exit(0);

    printf("hahahahahahaha\n");
}

int main(int argc, char const *argv[])
{
    printf("hello world\n");

    myfun();

    printf("welcome to hqyj\n");

    return 0;
}

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

void myexit()
{
    printf("这是进程结束后执行的最后一个代码\n");
}

void myfun()
{
    printf("nihao beijing");
    
    //return如果放在main函数中执行,可以结束当前进程,
    //但是如果是在子函数中执行,只能退出当前函数
    //return ;

    //exit函数不管在哪执行,都会结束整个进程
    //exit和_exit的区别是
    //exit是库函数,会自动刷新缓冲区
    //_exit是系统调用,不会刷新缓冲区
    exit(0);
    //_exit(0);

    printf("hahahahahahaha\n");
}

int main(int argc, char const *argv[])
{
    //当进程结束之后,还是可以执行代码的,
    //所执行的代码是atexit的回调函数
    atexit(myexit);

    printf("hello world\n");

    myfun();

    printf("welcome to hqyj\n");

    return 0;
}

4. wait()/waitpid()

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:
阻塞等待子进程的状态(子进程退出状态)改变
参数:
pid:指定要等待的子进程
<-1   只阻塞等待进程组id等于这个值的绝对值的组中任意一个子进程
-1    阻塞等待所有子进程的退出状态
0    阻塞等待进程组id等于当前进程的进程号的组中任意一个子进程
>0   阻塞等待子进程的进程号等于这个值的子进程
wstatus:
保存子进程状态改变值
options:
选项
0        阻塞
WNOHANG  非阻塞     
返回值:
成功:
退出的子进程的进程号
失败:
-1

wait(NULL) <==> waitpid(-1, NULL, 0);

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

int main(int argc, char const *argv[])
{
    pid_t pid;
    if((pid = fork()) == -1)
    {
        perror("fork error");
        exit(1);
    }
    else if(pid > 0) //父进程
    {
        int ret;
        printf("父进程正在执行...\n");

        //父进程调用wait函数阻塞等待子进程的退出状态
        //wait(NULL);
        waitpid(-1, NULL, 0);

        printf("父进程也执行完毕了\n");
        exit(0);
    }
    else //子进程
    {
        int i;
        printf("子进程正在执行...\n");
        for(i = 1; i <= 5; i++)
        {
            printf("hello world\n");
            sleep(1);
        }

        exit(0);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
c语言提供了一些用于进程操作相关函数。下面简要介绍几个常用的函数。 1. fork()函数:该函数用于创建新的进程。调用该函数会复制当前进程,使得原进程和新进程同时运行。原进程称为父进程,新进程称为子进程。父子进程的代码段和全局变量相同,但拥有独立的栈空间和唯一的进程ID。 2. exec()函数族:exec函数族用于在一个进程中执行新的程序。这些函数会在调用进程的地址空间中加载新的程序,并开始执行。exec函数族的几个常用函数有:execv()、execvp()、execve()。这些函数通过传递命令行参数、环境变量等信息,用新程序替换当前进程。 3. wait()函数:该函数用于使父进程等待子进程执行结束,并获取其退出状态。当子进程终止时,父进程可以根据wait函数返回的状态信息,判断子进程的终止方式和退出状态。如果子进程尚未终止,调用wait函数会使父进程阻塞,直到有子进程结束。 4. kill()函数:该函数用于向指定的进程发送信号。进程之间可以通过信号来通信,比如终止进程、暂停进程等。kill函数通过指定目标进程进程ID和信号编号,向目标进程发送信号。 5. getpid()函数:该函数用于获取当前进程进程ID。每个进程有唯一的进程ID,可以通过getpid函数获取该进程ID。这对于进行进程管理和进程间通信很有用。 总之,C语言提供了丰富的进程操作相关函数,可以用于创建、替换、等待进程,以及发送信号等操作。这些函数进程管理和进程间通信提供了丰富的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐的记事本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值