面试题答案
一键面试使用信号量解决消息队列访问同步问题
-
初始化信号量: 在使用信号量前,需要先创建并初始化信号量。例如,使用
semget
函数创建信号量集,然后使用semctl
函数初始化信号量的值。 -
获取信号量: 在进程访问消息队列前,获取信号量。如果信号量的值为0,进程会阻塞等待信号量的值变为1。可以使用
semop
函数来获取信号量。 -
释放信号量: 在进程完成对消息队列的访问后,释放信号量,将信号量的值加1,允许其他进程获取信号量并访问消息队列。同样使用
semop
函数来释放信号量。
异常处理
-
队列已满: 当发送消息时,如果消息队列已满,
msgsnd
函数会返回-1,并且errno
被设置为EAGAIN
或ENOMEM
。此时,可以选择等待一段时间后重试发送,或者采取其他替代策略。 -
消息类型不匹配: 当接收消息时,如果指定的消息类型在队列中不存在,
msgrcv
函数会返回-1,并且errno
被设置为EINVAL
。可以选择调整接收消息的类型,或者进行相应的错误处理。
代码示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <unistd.h>
#include <string.h>
#define MSG_SIZE 128
#define SEM_KEY 1234
#define MSG_KEY 5678
// 消息结构
typedef struct msgbuf {
long mtype;
char mtext[MSG_SIZE];
} msgbuf;
// 信号量操作函数
void semaphore_p(int semid) {
struct sembuf sem_op;
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = SEM_UNDO;
semop(semid, &sem_op, 1);
}
void semaphore_v(int semid) {
struct sembuf sem_op;
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = SEM_UNDO;
semop(semid, &sem_op, 1);
}
int main() {
int msgid, semid;
msgbuf msg;
// 创建消息队列
msgid = msgget(MSG_KEY, IPC_CREAT | 0666);
if (msgid == -1) {
perror("msgget");
exit(1);
}
// 创建信号量
semid = semget(SEM_KEY, 1, IPC_CREAT | 0666);
if (semid == -1) {
perror("semget");
msgctl(msgid, IPC_RMID, NULL);
exit(1);
}
// 初始化信号量
if (semctl(semid, 0, SETVAL, 1) == -1) {
perror("semctl");
msgctl(msgid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID, NULL);
exit(1);
}
// 发送消息
semaphore_p(semid);
msg.mtype = 1;
strcpy(msg.mtext, "Hello, Message Queue!");
if (msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
if (errno == EAGAIN) {
printf("Message queue is full. Retry later.\n");
} else {
perror("msgsnd");
}
}
semaphore_v(semid);
// 接收消息
semaphore_p(semid);
if (msgrcv(msgid, &msg, MSG_SIZE, 1, 0) == -1) {
if (errno == EINVAL) {
printf("Message type not found.\n");
} else {
perror("msgrcv");
}
} else {
printf("Received message: %s\n", msg.mtext);
}
semaphore_v(semid);
// 删除消息队列和信号量
msgctl(msgid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID, NULL);
return 0;
}
以上代码展示了如何使用信号量来同步对消息队列的访问,并处理发送和接收消息过程中的错误。