实验步骤:
-
第一篇进程的编译与运行:
- 首先,编译并运行第一篇代码。该进程在运行时会创建一个共享内存段,并初始化一个信号量,将其值减少至2。随后,进程会调用
pause()
函数,模拟正在处理一个大文件的情景,进入暂停状态。
- 首先,编译并运行第一篇代码。该进程在运行时会创建一个共享内存段,并初始化一个信号量,将其值减少至2。随后,进程会调用
-
第二篇进程的编译与运行:
- 接着,在一个新的独立命令窗口中,编译并运行第二篇代码。该进程尝试访问第一篇进程创建的共享内存。然而,由于信号量的值已被第一篇进程减少至0,第二篇进程会因无法获取信号量而被阻塞,无法继续执行。
-
唤醒第一篇进程:
- 在另一个命令窗口中,使用
kill -ALRM pid
命令发送信号唤醒第一篇进程。这个信号模拟了大文件处理完成的情况,唤醒后第一篇进程会释放信号量。
- 在另一个命令窗口中,使用
-
继续运行第二篇进程:
- 在信号量被释放后,第二篇进程将能够正常获取信号量并访问共享内存,继续其执行过程。最后,第二篇进程会完成对共享内存的处理并退出,同时清理删除共享内存段和信号量集。
-
验证实验结果:
- 运行
ipcs
命令检查系统中是否还存在共享内存段和信号量集。如果列表为空,说明实验顺利完成,资源已被正常清理。
- 运行
实验原理:
第一篇进程创建了一个共享内存段和一个信号量,并进入暂停状态,模拟长时间的文件处理。第二篇进程试图访问该共享内存,但由于信号量已被减少至0,它会被阻塞。通过在独立的命令窗口中发送信号来唤醒第一篇进程,第一篇进程将释放信号量,使第二篇进程能够继续执行。整个实验展示了进程间通过信号量和共享内存进行同步与通信的机制,并通过适当的资源管理来确保系统资源不会泄露。
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> //System V信号量
#include <semaphore.h> //POSIX信号量
#include <sys/shm.h> //System V共享内存
#include <sys/mman.h> //POSIX共享内存
#include <sys/msg.h> //System V消息队列
#include <mqueue.h> //POSIX消息队列
// 信号处理逻辑
void signal_handler(int signum)
{
printf("$$$%s$$$\n", strsignal(signum));
}
// 查看共享内存状态
void ipc_stat(int shmid)
{
struct shmid_ds shm_desc;
// 函数正常退出后信息被储存在shm_desc
if (shmctl(shmid, IPC_STAT, &shm_desc) == -1)
{
perror("shmctl");
}
printf("shm creator: %d\n", shm_desc.shm_cpid);
printf("shm size: %zu\n", shm_desc.shm_segsz);
printf("shm attaches: %ld\n", shm_desc.shm_nattch);
}
void sem_op(int semid, int sem_op)
{
// 信号量pv操作 -1 +1
struct sembuf sem_buffer = {0};
sem_buffer.sem_num = 0;
sem_buffer.sem_op = sem_op;
sem_buffe