// 设计一个程序,作为进程A,
// 进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,
// 要求集合中的信号量的初值为1,然后再设计2个程序,分别是进程B和进程C,
// 要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。
// 提示:进程A、进程B、进程C需要使用共享内存作为临界资源的访问。
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/wait.h>
/********************************************************/
//优化前
// 定义一个联合体
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
// 初始化信号量
int init_sem(int sem_id, int init_value)
{
union semun sem_union;
sem_union.val = init_value;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
{
perror("Initialize semaphore");
return -1;
}
return 0;
}
int main(int argc, char const *argv[])
{
// 创建一个信号量集
int sem_id = semget(ftok("./mysem", 1), 1, 0666 | IPC_CREAT);
if (sem_id == -1)
{
perror("Create semaphore set");
return -1;
}
// 初始化信号量
if (init_sem(sem_id, 1) == -1)
{
return -1;
}
// 创建共享内存
int shm_id = shmget(ftok("./myshm", 1), sizeof(int), 0666 | IPC_CREAT);
if (shm_id == -1)
{
perror("Create shared memory");
return -1;
}
// 将共享内存连接到当前进程的地址空间
int *shmaddr = (int *)shmat(shm_id, NULL, 0);
if (shmaddr == (int *)-1)
{
perror("Attach shared memory");
return -1;
}
*shmaddr = 0; // 初始化共享内存中的变量
// 创建进程B
pid_t pid_b = fork();
if (pid_b == 0)
{
// 子进程B
struct sembuf sem_op;
while (1)
{
// 等待信号量
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_op, 1) == -1)
{
perror("semop wait");
exit(1);
}
// 进入临界区
(*shmaddr)++;
printf("Process B: a = %d\n", *shmaddr);
printf("Process B is accessing shared memory\n");
sleep(1);
// 释放信号量
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_op, 1) == -1)
{
perror("semop signal");
exit(1);
}
sleep(1);
}
exit(0);
}
else if (pid_b < 0)
{
perror("fork");
return -1;
}
// 等待进程B完成第一次操作
sleep(2);
// 创建进程C
pid_t pid_c = fork();
if (pid_c == 0)
{
// 子进程C
struct sembuf sem_op;
while (1)
{
// 等待信号量
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_op, 1) == -1)
{
perror("semop wait");
exit(1);
}
// 进入临界区
printf("Process C: a = %d\n", *shmaddr);
printf("Process C is accessing shared memory\n");
sleep(1);
// 释放信号量
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_op, 1) == -1)
{
perror("semop signal");
exit(1);
}
sleep(1);
}
exit(0);
}
else if (pid_c < 0)
{
perror("fork");
return -1;
}
// 等待进程B和进程C结束
waitpid(pid_b, NULL, 0);
waitpid(pid_c, NULL, 0);
// 断开共享内存
if (shmdt(shmaddr) == -1)
{
perror("shmdt error");
exit(-1);
}
// 删除共享内存
shmctl(shm_id, IPC_RMID, 0);
// 删除信号量集合
semctl(sem_id, 0, IPC_RMID);
return 0;
}
/**********************************************/
void process_task(int sem_id, int *shmaddr, const char *process_name)
{
struct sembuf sem_op;
while (1)
{
// 等待信号量
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_op, 1) == -1)
{
perror("semop wait");
exit(1);
}
// 进入临界区
if (strcmp(process_name, "Process B") == 0)
{
(*shmaddr)++;
printf("%s: a = %d\n", process_name, *shmaddr);
}
printf(" 进程 %s \n", process_name);
sleep(1);
// 释放信号量
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_op, 1) == -1)
{
perror("semop signal");
exit(1);
}
sleep(1);
}
}
int main(int argc, char const *argv[])
{
// 创建一个信号量集
int sem_id = semget(ftok("./mysem", 1), 1, 0666 | IPC_CREAT);
if (sem_id == -1)
{
perror("Create semaphore set");
return -1;
}
// 初始化信号量
if (init_sem(sem_id, 1) == -1)
{
return -1;
}
// 创建共享内存
int shm_id = shmget(ftok("./myshm", 1), sizeof(int), 0666 | IPC_CREAT);
if (shm_id == -1)
{
perror("Create shared memory");
return -1;
}
// 将共享内存连接到当前进程的地址空间
int *shmaddr = (int *)shmat(shm_id, NULL, 0);
if (shmaddr == (int *)-1)
{
perror("Attach shared memory");
return -1;
}
*shmaddr = 0; // 初始化共享内存中的变量
// 创建进程B
pid_t pid_b = fork();
if (pid_b == 0)
{
// 子进程B
process_task(sem_id, shmaddr, "Process B");
exit(0);
}
else if (pid_b < 0)
{
perror("fork");
return -1;
}
// 创建进程C
pid_t pid_c = fork();
if (pid_c == 0)
{
// 子进程C
process_task(sem_id, shmaddr, "Process C");
printf("进程C中数值不变 %d\n", *shmaddr);
exit(0);
}
else if (pid_c < 0)
{
perror("fork");
return -1;
}
// 等待进程B和进程C结束
waitpid(pid_b, NULL, 0);
waitpid(pid_c, NULL, 0);
// 断开共享内存
if (shmdt(shmaddr) == -1)
{
perror("shmdt error");
exit(-1);
}
// 删除共享内存
shmctl(shm_id, IPC_RMID, 0);
// 删除信号量集合
semctl(sem_id, 0, IPC_RMID);
return 0;
}