题目:有一个盘子,父亲放入苹果,母亲放入桔子,女儿取出苹果,儿子取出桔子。
同步关系:父亲放苹果和女儿取苹果 && 母亲放桔子和儿子取桔子
互斥关系:父亲放苹果和母亲放桔子
下面是源代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main(int argc, char *argv[])
{
struct sembuf P, V;
union semun arg;
if (argc != 3) { //命令行参数个数必须为3
printf("usage: ./sem <APPLE> <ORANGE>\n");
exit(1);
}
int APPLE = atoi(argv[1]); //父亲放入的苹果数
int ORANGE = atoi(argv[2]); //母亲放入的桔子数
int getappleid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666); //申请共享内存
int getorangeid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666);
int *getapple = (int*) shmat(getappleid, 0, 0); //绑定共享内存
int *getorange = (int*) shmat(getorangeid, 0, 0);
*getapple = 0; //初始化取出苹果数为0
*getorange = 0; //初始化取出桔子数为0
int empty = semget(IPC_PRIVATE, 1, IPC_CREAT|0666); //盘子是否为空的信号量
int apple = semget(IPC_PRIVATE, 1, IPC_CREAT|0666); //盘子中是否有苹果的信号量
int orange = semget(IPC_PRIVATE, 1, IPC_CREAT|0666); //盘子中是否有桔子的信号量
int mutex = semget(IPC_PRIVATE, 1, IPC_CREAT|0666); //放入盘子和取出盘子的互斥信号量
arg.val = 1;
if (semctl(empty, 0, SETVAL, arg) == -1) //设置信号量
perror("semctl setval error");
arg.val = 0;
if (semctl(apple, 0, SETVAL ,arg) == -1)
perror("semctl setval error");
arg.val = 0;
if (semctl(orange, 0, SETVAL, arg) == -1)
perror("semctl setval error");
arg.val = 1;
if (semctl(mutex, 0, SETVAL, arg) == -1)
perror("semctl setval error");
P.sem_num = 0; //定义P、V操作
P.sem_op = -1;
P.sem_flg = SEM_UNDO;
V.sem_num = 0;
V.sem_op = 1;
V.sem_flg = SEM_UNDO;
if (fork() == 0) { //父亲进程
int i = 0;
for (; i < APPLE; i++) { //循环放入苹果
semop(empty, &P, 1);
semop(mutex, &P, 1);
printf("Father put APPLE\n");
semop(mutex, &V, 1);
semop(apple, &V, 1);
}
sleep(2);
printf("Father is over!\n");
exit(0);
} else {
if (fork() == 0) { //母亲进程
int i = 0;
for (; i < ORANGE; i++) { //循环放入桔子
semop(empty, &P, 1);
semop(mutex, &P, 1);
printf("Mother put ORANGE\n");
semop(mutex, &V, 1);
semop(orange, &V, 1);
sleep(1);
}
printf("Mother is over!\n");
exit(0);
} else {
if (fork() == 0) { //女儿进程
while (1) { //取出苹果
if (*getapple == APPLE) break;
semop(apple, &P, 1);
semop(mutex, &P, 1);
printf("\tDaughter get APPLE!\n\n");
(*getapple)++;
semop(mutex, &V, 1);
semop(empty, &V, 1);
sleep(1);
}
printf("\tDaughter get all APPLE!\n\n");
exit(0);
} else {
if (fork() == 0) { //儿子进程
while (1) { //取出桔子
if (*getorange == ORANGE) break;
semop(orange, &P, 1);
semop(mutex, &P, 1);
printf("\tSon get ORANGE!\n\n");
(*getorange)++;
semop(mutex, &V, 1);
semop(empty, &V, 1);
sleep(1);
}
printf("\tSon get all ORANGE!\n\n");
exit(0);
}
}
}
}
wait(0); //等待子进程结束
wait(0);
wait(0);
wait(0);
printf("\nAll processor end!\n\n");
shmdt(getapple); //释放共享内存
shmctl(getappleid, IPC_RMID, 0);
shmdt(getorange);
shmctl(getorangeid, IPC_RMID, 0);
semctl(empty, IPC_RMID, 0); //释放信号量
semctl(apple, IPC_RMID, 0);
semctl(orange, IPC_RMID, 0);
semctl(mutex, IPC_RMID, 0);
exit(0);
}
上面的代码是最终能在所有Linux下运行的版本。之前因为头文件是 linux/sem.h 和 linux/shm.h 导致无法在部分linux下运行。我看见Unix高级编程上面用的 sys/sem.h 和 sys/shm.h,并结合下面的文章对之前的代码进行了修改。