面试题答案
一键面试设计思路
- 数据结构设计:
- 环形缓冲区:使用环形缓冲区来存储实时数据。环形缓冲区可以高效地处理连续数据的读写,特别适合高频率更新的场景。它能避免频繁的内存分配和释放,减少内存碎片。
- 元数据结构:设计一个元数据结构来记录共享内存的状态,比如当前缓冲区的读写位置、数据版本号等信息。数据版本号可以帮助读取进程判断数据是否为最新。
- 操作逻辑设计:
- 写操作:负责更新数据的少数进程在写操作时,首先获取共享内存的写锁(如使用信号量实现)。更新数据后,更新元数据中的数据版本号,并释放写锁。
- 读操作:大量读取进程在读取数据前,先获取读锁(同样可使用信号量实现读 - 写锁机制)。读取数据前,先检查元数据中的数据版本号,若版本号未更新,则可以直接读取之前缓存的数据,减少实际从共享内存读取的次数。读取完成后,释放读锁。
关键代码片段
- 共享内存初始化:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#define SHM_SIZE 1024 // 共享内存大小
typedef struct {
int read_index;
int write_index;
int data_version;
// 假设实时数据是int类型,实际可根据需求更改
int data[SHM_SIZE];
} SharedMem;
int main() {
key_t key;
int shmid;
SharedMem *shared_mem;
// 生成唯一的键值
if ((key = ftok(".", 'a')) == -1) {
perror("ftok");
return 1;
}
// 创建共享内存段
if ((shmid = shmget(key, sizeof(SharedMem), IPC_CREAT | 0666)) == -1) {
perror("shmget");
return 1;
}
// 连接共享内存段到当前进程的地址空间
shared_mem = (SharedMem *)shmat(shmid, 0, 0);
if (shared_mem == (void *)-1) {
perror("shmat");
return 1;
}
// 初始化元数据
shared_mem->read_index = 0;
shared_mem->write_index = 0;
shared_mem->data_version = 0;
// 后续可进行读写操作
// 分离共享内存
if (shmdt(shared_mem) == -1) {
perror("shmdt");
return 1;
}
// 删除共享内存段
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl");
return 1;
}
return 0;
}
- 写操作:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#define SHM_SIZE 1024
typedef struct {
int read_index;
int write_index;
int data_version;
int data[SHM_SIZE];
} SharedMem;
int main() {
key_t key;
int shmid;
SharedMem *shared_mem;
sem_t *write_sem;
if ((key = ftok(".", 'a')) == -1) {
perror("ftok");
return 1;
}
if ((shmid = shmget(key, sizeof(SharedMem), 0666)) == -1) {
perror("shmget");
return 1;
}
shared_mem = (SharedMem *)shmat(shmid, 0, 0);
if (shared_mem == (void *)-1) {
perror("shmat");
return 1;
}
// 初始化写信号量
if ((write_sem = sem_open("/write_sem", 0)) == SEM_FAILED) {
perror("sem_open");
return 1;
}
// 获取写锁
sem_wait(write_sem);
// 模拟写数据
shared_mem->data[shared_mem->write_index] = 42;
shared_mem->write_index = (shared_mem->write_index + 1) % SHM_SIZE;
shared_mem->data_version++;
// 释放写锁
sem_post(write_sem);
if (shmdt(shared_mem) == -1) {
perror("shmdt");
return 1;
}
sem_close(write_sem);
return 0;
}
- 读操作:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#define SHM_SIZE 1024
typedef struct {
int read_index;
int write_index;
int data_version;
int data[SHM_SIZE];
} SharedMem;
int main() {
key_t key;
int shmid;
SharedMem *shared_mem;
sem_t *read_sem;
if ((key = ftok(".", 'a')) == -1) {
perror("ftok");
return 1;
}
if ((shmid = shmget(key, sizeof(SharedMem), 0666)) == -1) {
perror("shmget");
return 1;
}
shared_mem = (SharedMem *)shmat(shmid, 0, 0);
if (shared_mem == (void *)-1) {
perror("shmat");
return 1;
}
// 初始化读信号量
if ((read_sem = sem_open("/read_sem", 0)) == SEM_FAILED) {
perror("sem_open");
return 1;
}
// 获取读锁
sem_wait(read_sem);
int local_version = shared_mem->data_version;
// 模拟读数据
int value = shared_mem->data[shared_mem->read_index];
shared_mem->read_index = (shared_mem->read_index + 1) % SHM_SIZE;
// 释放读锁
sem_post(read_sem);
if (shmdt(shared_mem) == -1) {
perror("shmdt");
return 1;
}
sem_close(read_sem);
return 0;
}
以上代码通过环形缓冲区作为数据结构,结合信号量实现的读写锁机制,来优化共享内存操作性能,并防止数据丢失或不一致。在实际应用中,还需要考虑更多的错误处理和边界情况。