当前位置: 首页 > news >正文

实验三 进程间通信实验

一、实验目的

1、了解什么是信号。

2、熟悉LINUX系统中进程之间软中断通信的基本原理。

3、理解进程的同步关系。

4、掌握用信号实现进程间的同步操作。

5、了解什么是管道。

6、熟悉UNIX/LINUX支持的管道通信方式。

、实验内容

1、阅读下列程序,执行程序并给出结果截屏,分析程序功能。(2分)

1) #include<unistd.h>

#include<signal.h>

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

int k;

void func()

{   k=0; }

main()

{   int p;

        while((p=fork())==-1);

        if(p==0) //子进程

        {   k=1;

            signal(10,func);

            while(k!=0);

            printf("Child process is killed by parent!\n");

        }

        else //父进程

        {   sleep(1);

            kill(p,10);

            wait(0);

            printf("Parent process has killed!\n");

        }  

}

编译及执行过程和结果截屏:

程序实现功能(父进程和子进程分别做了什么?):

父进程创建子进程,并在创建成功后,等待1秒钟后向子进程发送信号10(SIGUSR1)。子进程在收到信号后,将k设置为0,进入循环等待k为0,并在k为0时输出"Child process is killed by parent!"。父进程在发送信号后,等待子进程结束,并在子进程结束后输出"Parent process has killed!"。

  1. #include<unistd.h>

#include<signal.h>

#include<stdio.h>

int k=1;

void func()

{   k=0; }

main()

{

        signal(SIGINT,func);

        while(k!=0);

        printf("\n main process is killed by keybreak!\n");

}

编译及执行过程和运行结果截屏:

解释程序实现的功能:

程序中定义了一个全局变量k,并将其初始值设置为1。然后通过signal函数将SIGINT信号(键盘中断信号)与一个自定义的信号处理函数func关联起来。在信号处理函数func中,将全局变量k的值设置为0,表示程序需要结束。在主函数中,通过一个while循环来监测k的值,如果k的值不为0,则一直循环。当用户在键盘上按下Ctrl+C键时,会触发SIGINT信号,从而调用信号处理函数func,将k的值设置为0,退出循环。最后,程序会打印出一条提示信息,表示主进程被键盘中断信号终止。

2、编写一段程序,使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按ctrl+c键),当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后,分别输出下列信息后终止: 

                       Child process 1 is killed by parent!

                       Child process 2 is killed by parent!

父进程等待两个子进程终止后,输出以下信息后终止:

                        Parent process is killed!

要求给出编译及执行过程和运行结果截屏。(2分)

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/wait.h>

pid_t child_process1;

pid_t child_process2;

void signal_handler(int signum) {

    kill(child_process1, SIGINT);

    kill(child_process2, SIGINT);

}

void child1_signal_handler(int signum) {

    printf("Child process 1 is killed by parent!\n");

    exit(0);

}

void child2_signal_handler(int signum) {

    printf("Child process 2 is killed by parent!\n");

    exit(0);

}

int main() {

    child_process1 = fork();

   

    if (child_process1 == 0) {

        // Child process 1

        signal(SIGINT, child1_signal_handler);

        while(1);

    }

   

    child_process2 = fork();

   

    if (child_process2 == 0) {

        // Child process 2

        signal(SIGINT, child2_signal_handler);

        while(1);

    }

   

    if (child_process1 > 0 && child_process2 > 0) {

        // Parent process

        signal(SIGINT, signal_handler);

        wait(NULL);

        wait(NULL);

        printf("Parent process is killed!\n");

        exit(0);

    }

   

    return 0;

}

编译及执行过程和运行结果截屏:

3、编写程序,利用信号实现司机售票员同步操作问题。要求给出编译及运行过程和结果截图。(2分)

参考程序框架:

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/wait.h>

int k;

void func()

{

    k = 0;

}

int main()

{

    int p;

    int count = 3;

   

    signal(12, func);

   

    while ((p = fork()) == -1);

   

    if (p > 0) // 司机进程

    {

        while (count)

        {

            k = 1;

            sleep(1);

            printf("driver: drive\n");

            printf("driver: stop\n");

           

            // 发送信号给售票员

            kill(p, 10);

           

            while (k);

           

            printf("driver: start\n");

            count--;

        }

    }

    else // 售票员进程

    {

        signal(10, func);

       

        while (count)

        {

            k = 1;

            printf("conductor: sell ticket.\n");

           

            while (k);

           

            printf("conductor: open door.\n");

            printf("conductor: close door.\n");

           

            // 取得司机进程的识别码

            pid_t driver_pid = getppid();

           

            // 发送信号给司机

            kill(driver_pid, 12);

           

            count--;

        }

    }

   

    return 0;

}编译及执行过程和结果截屏:

4、编制一段程序,实现进程的管道通信。使用pipe()建立一条管道线。两个子进程p1和p2分别向管道各写一句话:

            Child 1 is sending message!

            Child 2 is sending message!

而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。(1分)

<参考程序>

#include<unistd.h>

#include<signal.h>

#include<stdio.h>

#include<stdlib.h>

int pid1,pid2;

main()

{   int fd[2];

    char OutPipe[100],InPipe[100];

    pipe(fd);

    while((pid1=fork())== -1);

    if(pid1==0)

    {   sprintf(OutPipe,"child 1 process is sending message!");

        write(fd[1],OutPipe,50);

        sleep(5);

        exit(0);

    }

    else

    {   while((pid2=fork())==-1);

        if(pid2==0)

        {   sprintf(OutPipe,"child 2 process is sending message!");

            write(fd[1],OutPipe,50);

            sleep(5);

            exit(0);

        }

        else

        {   wait(0);

            read(fd[0],InPipe,50);

            printf("%s\n",InPipe);

            wait(0);

            read(fd[0],InPipe,50);

            printf("%s\n",InPipe);

            exit(0);

        }

    }

}

编译及执行过程和运行结果截屏。

5、在父进程中用pipe()建立一条管道线,往管道里写信息,两个子进程接收父进程发送的信息。(2分)

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/wait.h>

#define BUFFER_SIZE 100

int main() {

    int fd[2]; // 创建一个包含两个文件描述符的数组,用于存放管道的读端和写端

    pid_t pid1, pid2; // 用于存放子进程的进程ID

    char buffer[BUFFER_SIZE];

    // 创建管道

    if (pipe(fd) == -1) {

        fprintf(stderr, "Pipe failed");

        return 1;

    }

    // 创建第一个子进程

    pid1 = fork();

    if (pid1 < 0) {

        fprintf(stderr, "Fork failed");

        return 1;

    } else if (pid1 == 0) {

        // 子进程1从管道中读取信息,并输出到屏幕上

        close(fd[1]); // 关闭写端

        read(fd[0], buffer, BUFFER_SIZE);

        printf("Child Process 1 received message: %s\n", buffer);

        close(fd[0]); // 关闭读端

        exit(0);

    } else {

        // 父进程继续执行创建第二个子进程

        pid2 = fork();

        if (pid2 < 0) {

            fprintf(stderr, "Fork failed");

            return 1;

        } else if (pid2 == 0) {

            // 子进程2从管道中读取信息,并输出到屏幕上

            close(fd[1]); // 关闭写端

            read(fd[0], buffer, BUFFER_SIZE);

            printf("Child Process 2 received message: %s\n", buffer);

            close(fd[0]); // 关闭读端

            exit(0);

        } else {

            // 父进程往管道中写入信息

            close(fd[0]); // 关闭读端

            char message[] = "Hello from Parent Process!";

            write(fd[1], message, strlen(message) + 1);

            close(fd[1]); // 关闭写端

            wait(NULL); // 等待第一个子进程结束

            wait(NULL); // 等待第二个子进程结束

        }

    }

    return 0;

}

编译及执行过程和运行结果截屏。

6、编程用管道实现父子进程间的双向通信。要求给出设计思路,调试通过的程序和编译执行过程以及结果截屏。(附加题)

设计思路:

  1. 使用pipe()函数在父进程和子进程之间创建两条管道线,一条用于父进程向子进程传递信息,另一条用于子进程向父进程传递信息。
  2. 父进程创建两个子进程,并分别在每个子进程中使用不同的文件描述符来读取和写入信息。
  3. 父进程通过管道向子进程发送信息,子进程通过管道向父进程发送信息。

代码:

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/wait.h>

#define BUFFER_SIZE 100

int main() {

    int fd1[2], fd2[2]; // 创建两个管道

    pid_t pid1, pid2; // 用于存放子进程的进程ID

    char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];

    // 创建第一个管道

    if (pipe(fd1) == -1) {

        fprintf(stderr, "Pipe1 failed");

        return 1;

    }

    // 创建第二个管道

    if (pipe(fd2) == -1) {

        fprintf(stderr, "Pipe2 failed");

        return 1;

    }

    // 创建第一个子进程

    pid1 = fork();

    if (pid1 < 0) {

        fprintf(stderr, "Fork1 failed");

        return 1;

    } else if (pid1 == 0) {

        // 子进程1从管道1中读取信息,并输出到屏幕上

        close(fd1[1]); // 关闭管道1写端

        read(fd1[0], buffer1, BUFFER_SIZE);

        printf("Child Process 1 received message: %s\n", buffer1);

        // 子进程1向管道2写入信息

        close(fd2[0]); // 关闭管道2读端

        char message1[] = "Message from Child Process 1";

        write(fd2[1], message1, strlen(message1) + 1);

        close(fd1[0]); // 关闭管道1读端

        close(fd2[1]); // 关闭管道2写端

        exit(0);

    } else {

        // 创建第二个子进程

        pid2 = fork();

        if (pid2 < 0) {

            fprintf(stderr, "Fork2 failed");

            return 1;

        } else if (pid2 == 0) {

            // 子进程2从管道2中读取信息,并输出到屏幕上

            close(fd2[1]); // 关闭管道2写端

            read(fd2[0], buffer2, BUFFER_SIZE);

            printf("Child Process 2 received message: %s\n", buffer2);

            // 子进程2向管道1写入信息

            close(fd1[0]); // 关闭管道1读端

            char message2[] = "Message from Child Process 2";

            write(fd1[1], message2, strlen(message2) + 1);

            close(fd2[0]); // 关闭管道2读端

            close(fd1[1]); // 关闭管道1写端

            exit(0);

        } else {

            // 父进程向管道1写入信息

            close(fd1[0]); // 关闭管道1读端

            char message[] = "Message from Parent Process";

            write(fd1[1], message, strlen(message) + 1);

            // 父进程从管道2中读取信息,并输出到屏幕上

            close(fd2[1]); // 关闭管道2写端

            read(fd2[0], buffer2, BUFFER_SIZE);

            printf("Parent Process received message: %s\n", buffer2);

            close(fd1[1]); // 关闭管道1写端

            close(fd2[0]); // 关闭管道2读端

            wait(NULL); // 等待子进程1结束

            wait(NULL); // 等待子进程2结束

        }

    }

    return 0;

}

编译及执行过程和运行结果截屏。

三、实验总结和体会(1分)

在进行操作系统进程间通信的实验中,我通过使用管道来实现父进程和子进程之间的双向通信。这个实验让我更深入地理解了进程间通信的概念和原理。

通过使用管道,我实现了父进程向子进程发送信息,并且子进程可以接收到并处理这些信息。同时,子进程也能向父进程发送信息,父进程能够接收并处理这些信息。这种双向通信的方式非常实用,可以在多个进程之间实现数据的传递和共享。

在实验过程中,我注意到了管道的读写顺序。如果读写的顺序不一致,会导致阻塞并无法正常进行通信。此外,我还发现了管道在父子进程之间的传递性,即父进程可以通过管道向子进程传递信息,子进程也可以通过管道向父进程传递信息。

通过这个实验,我不仅加深了对进程间通信的理解,还学会了如何使用管道来实现进程间的双向通信。这将对我未来的学习和工作有很大的帮助。同时也让我更加深入地理解了操作系统的原理和机制。

相关文章:

  • Flink介绍——实时计算核心论文之Flink论文
  • 入门-C编程基础部分:19、输入 输出
  • nuxt3持久化存储全局变量
  • 深入浅出:Pinctrl与GPIO子系统详解
  • 模板偏特化 (Partial Specialization)
  • 开源漏洞扫描器:OpenVAS
  • Python函数与模块笔记
  • 【大模型实战】大模型推理加速框架 vllm 部署的方案
  • 使用String path = FileUtilTest.class.getResource(“/1.txt“).getPath(); 报找不到路径
  • 【Linux系统篇】:什么是信号以及信号是如何产生的---从基础到应用的全面解析
  • echart实现柱状图并实现柱子上方需要显示指定文字,以及悬浮出弹框信息,动态出现滚动条,动态更新x,y轴的坐标名称
  • linux sudo 命令介绍
  • NVIDIA高级辅助驾驶安全报告解析
  • 差分信号抗噪声原理:
  • 浔川代码编辑器v2.0(测试版)更新公告
  • 基于事件驱动的云原生后端架构设计:从理念到落地
  • 【多源01BFS】Codeforce:Three States
  • 基于Vulkan Specialization Constants的材质变体系统
  • JDK(java)安装及配置 --- app笔记
  • 低代码平台开发胎压监测APP
  • 北京顺义:做好潮白河大桥事故善后处置,举一反三排查风险
  • 纳斯达克中国金龙指数涨2.93%,金价油价大幅下挫
  • 职工疗休养如何告别千篇一律?安徽含山给出新解法
  • 男子为讨喜钱掰断劳斯莱斯小金人,警方:已介入处置
  • 世界读书日丨上图东馆开启残疾人无障碍文化服务
  • 经济日报刊文谈外卖平台仍试图凭补贴制造超低价:苦练内功摆脱“内卷式”竞争