A申请共享内存并对信号量进行初始化,然后进程B与C实现互斥
练习:设计一个程序,作为进程 A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2 个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。提示:进程 A、进程 B、进程C需要使用共享内存作为临界资源的访问。
进程A:
注意事项:假定sleep模拟的是程序的运行时间。如果在A或者B的sleep时间内,终止运行,会导致B或者C未能进行V操作,导致B和C都不能再次进行。此时需要重新执行A进程来对内存空间里面的数据初始化
/********************************************************************
*
* file name: shm_a.c
* author: 15070884254@163.com
* date: 2024年5月27日
* function: 新建一个共享内存,并初始化为0。
* note: 假定sleep模拟的是程序的运行时间。如 果在A或者B的sleep时间内,终止运行,会导致B或者C未能进行V操作,导致B和C都不能再次进行。此时需要重新执行A进程来对内存空间里面的数据初始化
*
* CopyRight (c) 15070884254@163.com All Right Reseverd
*
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>
/*****************************************************************************
* 函数名称: main
* 函数功能: 创建一个信号量,并对信号量初始化。创建一个共享内存,并初始化为0。
* 函数参数: int argc, char const *argv[]
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
int main(int argc, char const *argv[])
{
int *shm_a;
// 创建一个信号量
int sem_id = semget(ftok(".", 1), 1, IPC_CREAT | IPC_EXCL | 0664);
if (sem_id == -1) // 如果信号量存在,则直接打开
{
fprintf(stderr, "semget warning: errno: %d, %s\n", errno, strerror(errno));
sem_id = semget(ftok(".", 1), 1, 0664);
if (sem_id == -1) // 打开失败直接退出程序
{
fprintf(stderr, "semget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
// 设置信号量,并初始化
struct sembuf sops;
sops.sem_num = 0;
sops.sem_op = 1;
sops.sem_flg = 0;
if (semop(sem_id, &sops, 1) == -1)
{
fprintf(stderr, "semop error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
// 创建共享内存
int shm_id = shmget(ftok(".", 2), 4, IPC_CREAT | IPC_EXCL | 0664);
if (shm_id == -1) // 如果共享内存存在,则直接打开
{
fprintf(stderr, "shmget warning: errno: %d, %s\n", errno, strerror(errno));
shm_id = shmget(ftok(".", 2), 4, 0664);
if (shm_id == -1) // 打开失败直接退出程序
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
// 将共享内存连接到当前进程的地址空间
shm_a = (int *)shmat(shm_id, NULL, 0);
if (shm_a == (int *)(-1)) // 连接失败直接退出程序
{
fprintf(stderr, "shmat error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
// 对共享内存空间进行初始化
*shm_a = 0;
// 分离共享内存
if (shmdt(shm_a) == -1)
{
fprintf(stderr, "shmdt error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
return 0;
}
进程B:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>
/*****************************************************************************
* 函数名称: P
* 函数功能: 对信号量进行P操作(-1+sops.sem_op)
* 函数参数: int sem_id, struct sembuf *sops
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
static void P(int sem_id, struct sembuf *sops)
{
sops->sem_op = -1;
if (semop(sem_id, sops, 1) == -1)
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
/*****************************************************************************
* 函数名称: V
* 函数功能: 对信号量进行V操作(1+sops.sem_op)
* 函数参数: int sem_id, struct sembuf *sops
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
static void V(int sem_id, struct sembuf *sops)
{
sops->sem_op = 1;
if (semop(sem_id, sops, 1) == -1)
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
/*****************************************************************************
* 函数名称: main
* 函数功能: 通过对信号量进行PV操作,如果信号量小于0,则阻塞等待,如果大于0,则执行写操作
* 函数参数: int sem_id, struct sembuf *sops
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
int main(int argc, char const *argv[])
{
// 获取信号量id
int sem_id = semget(ftok(".", 1), 1, 0664);
if (sem_id == -1) // 获取失败直接退出程序
{
fprintf(stderr, "semget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
// 打开共享队列
int shm_id = shmget(ftok(".", 2), 4, 0664);
if (shm_id == -1) // 获取失败直接退出程序
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
// 获取共享内存的映射地址
int *shm_ptr = (int *)shmat(shm_id, NULL, 0);
int i = 0;
// 设置信号量buf
struct sembuf sops;
while (1)
{
// 初始化buf
memset(&sops, 0, sizeof(sops));
P(sem_id, &sops); // 执行操作前先‘P’一下
memcpy(shm_ptr, &i, sizeof(int)); // 执行写操作
sleep(10);
V(sem_id, &sops); // 执行操作前先‘V’一下
i++;
printf("修改i的值: %d\n", i);
}
return 0;
}
进程C:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>
/*****************************************************************************
* 函数名称: P
* 函数功能: 对信号量进行P操作(-1+sops.sem_op)
* 函数参数: int sem_id, struct sembuf *sops
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
static void P(int sem_id, struct sembuf *sops)
{
sops->sem_op = -1;
if (semop(sem_id, sops, 1) == -1)
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
/*****************************************************************************
* 函数名称: V
* 函数功能: 对信号量进行V操作(1+sops.sem_op)
* 函数参数: int sem_id, struct sembuf *sops
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
static void V(int sem_id, struct sembuf *sops)
{
sops->sem_op = 1;
if (semop(sem_id, sops, 1) == -1)
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
/*****************************************************************************
* 函数名称: main
* 函数功能: 通过对信号量进行PV操作,如果信号量小于0,则阻塞等待,如果大于0,则执行读操作
* 函数参数: int sem_id, struct sembuf *sops
* 返回结果: NONE
* 注意事项: NONE
* 函数作者: 15070884254@163.com
* 创建日期: 2024年5月28日
* 修改历史: 2024年5月28日
* 函数版本: 1.0
*
*****************************************************************************/
int main(int argc, char const *argv[])
{
// 获取信号量id
int sem_id = semget(ftok(".", 1), 1, 0664);
if (sem_id == -1) // 获取失败直接退出程序
{
fprintf(stderr, "semget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
// 打开共享队列
int shm_id = shmget(ftok(".", 2), 4, 0664);
if (shm_id == -1) // 获取失败直接退出程序
{
fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
exit(1);
}
// 获取共享内存的映射地址
int *shm_ptr = (int *)shmat(shm_id, NULL, 0);
int i = 0;
// 设置信号量buf
struct sembuf sops;
while (1)
{
// 初始化buf
memset(&sops, 0, sizeof(sops));
P(sem_id, &sops); // 执行操作前先‘P’一下
printf("new data: %d\n", *shm_ptr); // 执行读操作
V(sem_id, &sops); // 执行操作前先‘V’一下
sleep(3);
}
return 0;
}