【操作系统】实验三 进程通信---信号机制

实验名称: 实验三  进程通信---信号机制

实验目的: 

1. 熟悉 LINUX 支持的信号量机制、管道机制

2. 熟悉 LINUX 系统软中断通信的基本原理 

3. 掌握UNIX/LINUX的管道通信方式

实验内容:

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

Child process1 is killed by parent!

Child process2 is killed by parent!

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

Parent process is killed!

2. 分析利用软中断通信实现进程同步的机理。

软中断通信是一种通过软件实现的进程间通信方式。它的基本机理是利用操作系统提供的软中断机制,通过向指定的软中断号发送软中断信号来实现进程间的通信。

在Linux中,可以使用系统调用 int 0x80 触发一个软中断。通过在寄存器中设置不同的参数,可以实现各种系统调用,包括进程间通信。

3. 编写程序实现进程的管道通信。用系统调用 pipe( )建立一管道,二个子进程 P1 和 P2 分别向管道各写一句话:

Child 1 is sending a message!

Child 2 is sending a message!

父进程从管道中读出二个来自子进程的信息并显示(要求先接收 P1,后 P2)

算法设计与实现(附流程图和源代码):

1.

#include 

#include 

#include 

#include 

#include 

#include 



pid_t pid1, pid2; // 声明pid1和pid2变量



void child_process(int id) {

    printf("Child process%d is created!\n", id);



    while (1) {

        sleep(1); // 子进程持续运行

    }

}



void sig_handler(int signo) {

    if (signo == SIGINT) {

        printf("Parent process received SIGINT!\n");

        kill(pid1, SIGUSR1); // 向子进程1发送SIGUSR1信号

        kill(pid2, SIGUSR1); // 向子进程2发送SIGUSR1信号

    }

}



void child_sig_handler(int signo) {

    if (signo == SIGUSR1) {

        printf("Child process%d is killed by parent!\n", getpid() - getppid());

        exit(0);

    }

}



int main() {

    signal(SIGINT, sig_handler); // 设置父进程的信号处理函数



    pid1 = fork();

    if (pid1 == 0) {

        signal(SIGUSR1, child_sig_handler); // 设置子进程1的信号处理函数

        child_process(1);

    }



    pid2 = fork();

    if (pid2 == 0) {

        signal(SIGUSR1, child_sig_handler); // 设置子进程2的信号处理函数

        child_process(2);

    }



    int status;

    waitpid(pid1, &status, 0); // 等待子进程1终止

    waitpid(pid2, &status, 0); // 等待子进程2终止



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



    return 0;

}

流程图

   +-------------------+

  |   Main Process    |

  +-------------------+

         |

         | Fork() 1

         |

  +-------------------+

  |   Child Process1  |

  +-------------------+

         |

         | Fork() 2

         |

  +-------------------+

  |   Child Process2  |

  +-------------------+

         |

  +-------------------+

  |   Main Process    |

  |   SIGINT Handler  |

  |   SIGALRM Handler |

  |   Waiting         |

  |   (sleep)         |

  +-------------------+

         |

  +-------------------+

  |   Child Process1  |

  |   SIGINT Handler  |

  |   SIGALRM Handler |

  |   Waiting         |

  |   (sleep)         |

  +-------------------+

         |

  +-------------------+

  |   Child Process2  |

  |   SIGINT Handler  |

  |   SIGALRM Handler |

  |   Waiting         |

  |   (sleep)         |

  +-------------------+

         |

  +-------------------+

  |   Main Process    |

  |   SIGINT Handler  |

  |   SIGALRM Handler |

  |   Waiting         |

  |   (sleep)         |

  |   Send Signals    |

  |   to Child        |

  +-------------------+

         |

  +-------------------+

  |   Child Process1  |

  |   SIGINT Handler  |

  |   SIGALRM Handler |

  |   Waiting         |

  |   (sleep)         |

  |   Kill Self       |

  +-------------------+

         |

  +-------------------+

  |   Child Process2  |

  |   SIGINT Handler  |

  |   SIGALRM Handler |

  |   Waiting         |

  |   (sleep)         |

  |   Kill Self       |

  +-------------------+

         |

  +-------------------+

  |   Main Process    |

  |   Wait for Child  |

  |   Processes       |

  |   Exit            |

  +-------------------+


3. 

#include 

#include 

#include 

#include 

#include 



int pid1, pid2;



int main() {

    int fd[2];

    char outpipe[100], inpipe[100];

    pipe(fd);



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

    if (pid1 == 0) {

        lockf(fd[1], 1, 0);

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

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

        sleep(5);

        lockf(fd[1], 0, 0);

        exit(0);

    } else {

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

        if (pid2 == 0) {

            lockf(fd[1], 1, 0);

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

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

            sleep(5);

            lockf(fd[1], 0, 0);

            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);

        }

    }

}

流程图

  +-------------------+

  |   Main Process    |

  +-------------------+

         |

  +-------------------+

  |   Pipe Created    |

  |   (fd[0] and fd[1])|

  +-------------------+

         |

  +-------------------+

  |   fork() 1        |

  +-------------------+

         |

  +-------------------+

  |   Child Process1  |

  +-------------------+

         |

  +-------------------+

  |   lockf(write)     |

  |   Write Message   |

  |   sleep(5)        |

  |   lockf(unlock)   |

  |   Exit            |

  +-------------------+

         |

  +-------------------+

  |   Parent Process  |

  |   fork() 2        |

  +-------------------+

         |

  +-------------------+

  |   Child Process2  |

  +-------------------+

         |

  +-------------------+

  |   lockf(write)     |

  |   Write Message   |

  |   sleep(5)        |

  |   lockf(unlock)   |

  |   Exit            |

  +-------------------+

         |

  +-------------------+

  |   Parent Process  |

  |   wait(pid1)       |

  |   Read Message    |

  |   Print Message   |

  |   wait(pid2)       |

  |   Read Message    |

  |   Print Message   |

  |   Exit            |

  +-------------------+

调试过程及实验结果(附截图):

  1. 【操作系统】实验三 进程通信---信号机制_第1张图片

思考题:

  1. 实验内容1的程序段前面部分用了两个 wait(0),它们起什么作用?
    wait(0) 用于等待子进程的退出,参数为 0 表示等待任何一个子进程退出。
  2. 实验内容1的程序段中每个进程退出时都用了语句 exit(0),为什么?
    exit(0) 用于终止进程的执行,参数 0 表示正常退出。
  3. 为何预期的结果并未显示出?
    如果预期结果未显示出来,可能是由于程序执行时的环境或者其他因素导致的。你可以检查一下程序是否被正确编译和执行。
  4. 什么是进程同步? wait( )是如何实现进程同步的?
    进程同步是指多个进程之间按照一定的顺序执行,以保证资源的正确访问。wait() 是一个用于实现进程同步的系统调用,它可以让父进程等待子进程的退出,从而保证子进程的执行顺序。
  5. 实验内容3的程序中的 sleep(5)起什么作用?
    sleep(5) 让进程暂停执行,即睡眠5秒钟。在这里,它的作用是在子进程等待一段时间后再发送信号。
  6. 实验内容3中的子进程 1 和 2 为什么也能对管道进行操作?
    子进程1和2能够对管道进行操作是因为它们继承了父进程的文件描述符,包括管道的读端和写端。因此,它们可以使用这些文件描述符来进行读写操作。

实验小结:

实验小结:

在本次实验中,我们学习了以下几个重要的主题:

1. 进程间通信:通过使用管道,我们成功地实现了父进程和两个子进程之间的通信。管道提供了一个在进程间传递数据的简单方式。

2. 多进程编程:通过使用 `fork()` 系统调用,我们创建了多个子进程。这些子进程可以并发执行,各自有自己的独立执行环境。

3. 信号处理:我们在父进程中使用了信号处理函数来捕捉 `SIGINT` 信号(即按下 `Ctrl+C`),并向子进程发送了 `SIGUSR1` 信号。

4. 进程同步:在父进程中,我们使用 `wait()` 系统调用来等待子进程的退出,从而保证了子进程的执行顺序。

5. 文件描述符:通过创建管道,我们学习了如何使用文件描述符来进行读写操作。

6. 实验反思:在调试过程中,我们遇到了一些警告和错误,比如隐式声明 `wait()` 函数和未包含相应的头文件。这些问题在及时解决后,程序才能成功编译和执行。

总的来说,通过这次实验,我们加深了对进程间通信和多进程编程的理解,同时也熟悉了一些系统调用和信号处理的使用。同时,及时的调试和解决问题也是非常重要的一部分。

你可能感兴趣的:(操作系统,单片机,嵌入式硬件)