设计思路
- 共享内存分配:使用
shmat
函数将共享内存段附加到进程地址空间,shmget
函数用于创建或获取共享内存段。
- 同步机制:采用信号量(
semaphore
)来实现进程间的同步,确保在同一时间只有一个进程能够对共享内存进行写操作,多个进程可以同时进行读操作。使用读写锁(pthread_rwlock
)也可优化读写并发性能,读操作并发执行,写操作独占。
- 内存碎片管理:可以使用固定大小的内存块分配策略,预先将共享内存划分为多个固定大小的块,每次分配和释放都以这些块为单位,减少碎片产生。
- 提高访问效率:在共享内存中维护一个元数据区域,记录每个内存块的使用状态,这样在分配和释放内存时可以快速定位可用块。同时,尽量减少系统调用次数,例如批量处理多个内存操作。
核心代码片段
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>
#define SHM_SIZE 1024*1024 // 共享内存大小
#define BLOCK_SIZE 1024 // 固定内存块大小
#define NUM_BLOCKS (SHM_SIZE / BLOCK_SIZE)
// 共享内存结构体
typedef struct {
sem_t mutex; // 互斥信号量
sem_t wrt; // 写信号量
int block_status[NUM_BLOCKS]; // 每个内存块的使用状态,0表示空闲,1表示已使用
char data[SHM_SIZE]; // 共享数据区域
} SharedMemory;
// 获取共享内存
SharedMemory* get_shared_memory() {
key_t key = ftok(".", 'a');
if (key == -1) {
perror("ftok");
exit(1);
}
int shmid = shmget(key, sizeof(SharedMemory), IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget");
exit(1);
}
SharedMemory *shm = (SharedMemory*)shmat(shmid, NULL, 0);
if (shm == (void*)-1) {
perror("shmat");
exit(1);
}
// 初始化信号量和块状态
if (sem_init(&shm->mutex, 1, 1) == -1) {
perror("sem_init mutex");
exit(1);
}
if (sem_init(&shm->wrt, 1, 1) == -1) {
perror("sem_init wrt");
exit(1);
}
for (int i = 0; i < NUM_BLOCKS; i++) {
shm->block_status[i] = 0;
}
return shm;
}
// 分配内存块
void* allocate_block(SharedMemory *shm) {
sem_wait(&shm->mutex);
for (int i = 0; i < NUM_BLOCKS; i++) {
if (shm->block_status[i] == 0) {
shm->block_status[i] = 1;
sem_post(&shm->mutex);
return &shm->data[i * BLOCK_SIZE];
}
}
sem_post(&shm->mutex);
return NULL; // 没有可用块
}
// 释放内存块
void free_block(SharedMemory *shm, void* block) {
int index = ((char*)block - shm->data) / BLOCK_SIZE;
sem_wait(&shm->mutex);
if (index >= 0 && index < NUM_BLOCKS && shm->block_status[index] == 1) {
shm->block_status[index] = 0;
}
sem_post(&shm->mutex);
}
优化点说明
- 同步优化:读写锁相比信号量,读操作时允许更多并发,提高读性能。但需注意读写锁在跨进程使用时需要特殊处理(如使用
pthread_rwlockattr_setpshared
设置为进程间共享)。
- 内存分配优化:采用固定大小块分配策略减少碎片,若实际应用中数据大小变化较大,可考虑多级固定大小块或者自适应内存分配算法。
- 元数据管理:通过维护块状态数组,能快速定位空闲块,提升分配和释放效率。还可以使用更高效的数据结构如位图来进一步优化查找性能。
- 减少系统调用:在用户态缓存一些共享内存状态信息,尽量减少对
sem_wait
、sem_post
等系统调用的次数,提高整体效率。