smoker_question.h
#ifndef _SMOKER_QUESTION_H
#define _SMOKER_QUESTION_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <time.h>
// 鏉愭枡绫诲瀷
typedef enum { TOBACCO, PAPER, GLUE } Material;
// 鍒濆鍖栦俊鍙烽噺
int init_sem(int key, int value);
// P鎿嶄綔
void sem_wait(int semid);
// V鎿嶄綔
void sem_signal(int semid);
#endif
smoker_sem.c
#include "smoker_question.h"
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int init_sem(int key, int value) {
int semid = semget(key, 1, IPC_CREAT | 0666);
if (semid == -1) {
perror("semget failed");
exit(EXIT_FAILURE);
}
union semun arg;
arg.val = value;
if (semctl(semid, 0, SETVAL, arg) == -1) {
perror("semctl failed");
exit(EXIT_FAILURE);
}
return semid;
}
void sem_wait(int semid) {
struct sembuf op = {0, -1, 0};
semop(semid, &op, 1);
}
void sem_signal(int semid) {
struct sembuf op = {0, 1, 0};
semop(semid, &op, 1);
}
prac4.c
#include "smoker_question.h"
#include <sys/wait.h>
#define NUM_SMOKERS 3
// 鐢熶骇鑰呭伐浣滃嚱鏁?
void producer_work() {
// 鑾峰彇涓変釜淇″彿閲?
int sem_tobacco = semget(111, 1, 0666);
int sem_paper = semget(222, 1, 0666);
int sem_glue = semget(333, 1, 0666);
srand(time(NULL)); // 鍒濆鍖栭殢鏈虹瀛?
while (1) {
// 闅忔満閫夋嫨涓€绉嶇己澶辩殑鏉愭枡(鎻愪緵鍙﹀涓ょ)
int missing = rand() % 3;
switch (missing) {
case 0: // 缂虹儫鑽?鎻愪緵绾稿拰鑳舵按)
printf("Producer%d: providing PAPER and GLUE\n",getpid());
sem_signal(sem_tobacco);
break;
case 1: // 缂虹焊(鎻愪緵鐑熻崏鍜岃兌姘?
printf("Producer%d: providing TOBACCO and GLUE\n",getpid());
sem_signal(sem_paper);
break;
case 2: // 缂鸿兌姘?鎻愪緵鐑熻崏鍜岀焊)
printf("Producer%d: providing TOBACCO and PAPER\n",getpid());
sem_signal(sem_glue);
break;
}
sleep(1); // 绛夊緟鎶界儫鑰呭畬鎴?
}
}
// 娑堣垂鑰呭伐浣滃嚱鏁?
void smoker_work(Material material) {
const char *names[] = {"TOBACCO", "PAPER", "GLUE"};
// 鑾峰彇瀵瑰簲鐨勪俊鍙烽噺
int semid;
switch (material) {
case TOBACCO: semid = semget(111, 1, 0666); break; // 绛夊緟绾稿拰鑳舵按
case PAPER: semid = semget(222, 1, 0666); break; // 绛夊緟鐑熻崏鍜岃兌姘?
case GLUE: semid = semget(333, 1, 0666); break; // 绛夊緟鐑熻崏鍜岀焊
default: exit(EXIT_FAILURE);
}
while (1) {
sem_wait(semid); // 绛夊緟闇€瑕佺殑鏉愭枡缁勫悎
printf("Smoker%d with %s:smoking a cigarette\n",getpid(), names[material]);
sleep(1); // 妯℃嫙鎶界儫鏃堕棿
printf("Smoker%d with %s: Done smoking\n",getpid(), names[material]);
}
}
int main() {
// 鍒濆鍖栦笁涓俊鍙烽噺
init_sem(111, 0); // 绾稿拰鑳舵按
init_sem(222, 0); // 鐑熻崏鍜岃兌姘?
init_sem(333, 0); // 鐑熻崏鍜岀焊
// 鍒涘缓涓や釜鐢熶骇鑰呰繘绋?鐖惰繘绋嬪拰绗竴涓瓙杩涚▼)
pid_t producer_pid = fork();
if (producer_pid == 0) {
// 瀛愯繘绋嬩綔涓虹浜屼釜鐢熶骇鑰?
producer_work();
exit(0);
}
// 鐖惰繘绋嬩綔涓虹涓€涓敓浜ц€?
pid_t smoker_pids[NUM_SMOKERS];
int i;
for ( i = 0; i < NUM_SMOKERS; i++) {
smoker_pids[i] = fork();
if (smoker_pids[i] == 0) {
// 瀛愯繘绋嬩綔涓烘秷璐硅€?
smoker_work((Material)i);
exit(0);
}
}
// 鐖惰繘绋嬩篃浣滀负鐢熶骇鑰?
producer_work();
// 绛夊緟鎵€鏈夊瓙杩涚▼缁搒
for ( i = 0; i < NUM_SMOKERS; i++) {
waitpid(smoker_pids[i], NULL, 0);
}
waitpid(producer_pid, NULL, 0);
return 0;
}
Makefile
cc = gcc
CFLAGS = -Wall -g
TARGET = prac4
SRCS = prac4.c smoker_sem.c
all: $(TARGET)
$(TARGET): $(SRCS)
$(CC) $(CFLAGS) -o $(TARGET) $(SRCS)
clean:
rm -f $(TARGET)