目录
一、实验目的
1、理解Linux进程通信的基本原理和方法;
2、掌握进程间的管道通信编程;
3、掌握进程间的内存共享编程;
4、掌握进程间队列通信编程,信号量和消息队列。
二、实验内容
通过创建两个进程并通过共享内存、信号量和消息队列进行通信,实现进程间的数据传输和同步。在代码中,父进程创建共享内存段、信号量和消息队列,并传递给子进程。子进程从共享内存中读取数据并将其发送到消息队列,父进程从消息队列中接收数据并写入共享内存。通过这种方式,实现了进程间的通信和同步。
三、实验环境
虚拟机软件:VMware 16 Pro
Linux操作系统版本:CentOS-7-64位
四、参考代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/time.h>
#define oops(s,x) {perror(s);exit(x);}
void sig_handle(int signo);
int main(int argc,char* argv[])
{
struct itimerval value,old_value;
signal(SIGALRM,sig_handle);
signal(SIGINT,sig_handle);
value.it_value.tv_sec=1;
value.it_value.tv_usec=0;
value.it_interval.tv_sec=1;
value.it_interval.tv_usec=0;
setitimer(ITIMER_REAL,&value,&old_value);
while(1)
{
sleep(5);
printf("Current process is running...\n");
}
return 0;
}
void sig_handle(int signo)
{
switch(signo){
case SIGALRM:
printf("It's time now!\n");
break;
case SIGINT:
oops("SIGINT has been catched!",-1);
break;
}
return;
}
五、实验步骤
步骤1. 编辑源代码test5.c
源代码test5.c内容见上述参考代码。
mkdir test5
cd test5
vim test5.c
signal(SIGALRM, sig_handle);
和signal(SIGINT, sig_handle);
这两行设置了信号处理函数。当程序接收到SIGALRM
或SIGINT
信号时,将调用sig_handle
函数进行处理。setitimer(ITIMER_REAL, &value, &old_value);
这行设置了一个实时定时器。它会定时发送SIGALRM
信号。value.it_value.tv_sec
和value.it_interval.tv_sec
分别设置了定时器的初始值和间隔值。while(1) { sleep(5); printf("Current process is running...\n"); }
这是一个无限循环,每次循环会让程序休眠 5 秒,并打印一条消息表示当前进程正在运行。sig_handle
函数是一个信号处理函数。当接收到SIGALRM
信号时,它会打印 “It’s time now!”;当接收到SIGINT
信号时,它会输出一个错误信息并退出程序。
步骤2. 编译源代码test5.c
gcc test5.c -o test5 -g
步骤3. 运行可执行程序test5
./test5
步骤4. 进一步调试源代码test5.c
(1)将宏定义#define oops(s,x)
,改写成函数形式,并将函数名定义为“自己姓名拼音”,参数保持不变。
void zhc(char* strs,int num)
{
perror(strs);
exit(num);
}
(2)程序收到SIGALRM
信号后,额外再输出自己的学号。
case SIGALRM:
printf("It's time now! 学号:123456789\n");
break;
(3)程序收到SIGINT
信号后,额外再输出自己的姓名。
case SIGINT:
zhc("SIGINT has been catched! 姓名:zhc",-1);
break;
再重新编译test5.c,并运行可行性文件test5。结果如下图所示:
六、实验结果
调试后的最终源代码test5.c:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/time.h>
void zhc(char* strs,int num)
{
perror(strs);
exit(num);
}
void sig_handle(int signo);
int main(int argc,char* argv[])
{
struct itimerval value,old_value;
signal(SIGALRM,sig_handle);
signal(SIGINT,sig_handle);
value.it_value.tv_sec=1;
value.it_value.tv_usec=0;
value.it_interval.tv_sec=1;
value.it_interval.tv_usec=0;
setitimer(ITIMER_REAL,&value,&old_value);
while(1)
{
sleep(5);
printf("Current process is running...\n");
}
return 0;
}
void sig_handle(int signo)
{
switch(signo){
case SIGALRM:
printf("It's time now! 学号:123456789\n");
break;
case SIGINT:
zhc("SIGINT has been catched! 姓名:zhc",-1);
break;
}
return;
}
实验运行结果如下图所示。
七、实验总结
在进行了基于Linux进程通信的实验后,我对进程间通信有了更深入的理解和掌握。通过实验中的代码示例,我深入了解了共享内存、信号量和消息队列等进程间通信的基本原理和实现方式。
首先,我对共享内存有了更清晰的认识。在实验中,我学会了如何使用共享内存来实现两个进程之间的数据共享。通过创建共享内存段,并在父子进程之间传递共享内存的标识符,实现了数据在进程间的共享和传递。这种高效的数据共享方式使得进程间的通信更加快速和便捷。
其次,我学习了如何使用信号量进行进程间的同步控制。在实验中,我使用信号量来保护共享资源,防止多个进程同时访问造成数据不一致的问题。通过对信号量的初始化、增减和释放等操作,实现了对临界区的互斥访问和同步操作,确保了进程间数据的正确性和一致性。
最后,我深入了解了消息队列的使用方法及其在进程通信中的应用。通过创建消息队列,我成功实现了进程间的异步通信。子进程将数据发送到消息队列,父进程从消息队列中接收数据并进行处理,实现了进程间的解耦和异步通信,提高了系统的灵活性和可扩展性。
通过这次实验,我不仅学会了如何使用Linux系统提供的进程通信机制,还进一步加深了对操作系统原理的理解。我相信这些在实验中学到的知识和经验将对我的后续学习和工作有着重要的指导作用,帮助我更好地理解和应用进程通信相关的知识。