MST

星途 面试题库

面试题:C语言Linux共享内存复杂应用与优化

假设在一个高并发的Linux环境中,多个进程频繁地对共享内存进行读写操作。请用C语言设计一个高效的共享内存管理方案,不仅要保证数据的一致性和同步性,还要尽量减少内存碎片和提高访问效率。阐述设计思路,并给出核心代码片段及优化点说明。
25.4万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 共享内存分配:使用shmat函数将共享内存段附加到进程地址空间,shmget函数用于创建或获取共享内存段。
  2. 同步机制:采用信号量(semaphore)来实现进程间的同步,确保在同一时间只有一个进程能够对共享内存进行写操作,多个进程可以同时进行读操作。使用读写锁(pthread_rwlock)也可优化读写并发性能,读操作并发执行,写操作独占。
  3. 内存碎片管理:可以使用固定大小的内存块分配策略,预先将共享内存划分为多个固定大小的块,每次分配和释放都以这些块为单位,减少碎片产生。
  4. 提高访问效率:在共享内存中维护一个元数据区域,记录每个内存块的使用状态,这样在分配和释放内存时可以快速定位可用块。同时,尽量减少系统调用次数,例如批量处理多个内存操作。

核心代码片段

#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);
}

优化点说明

  1. 同步优化:读写锁相比信号量,读操作时允许更多并发,提高读性能。但需注意读写锁在跨进程使用时需要特殊处理(如使用pthread_rwlockattr_setpshared设置为进程间共享)。
  2. 内存分配优化:采用固定大小块分配策略减少碎片,若实际应用中数据大小变化较大,可考虑多级固定大小块或者自适应内存分配算法。
  3. 元数据管理:通过维护块状态数组,能快速定位空闲块,提升分配和释放效率。还可以使用更高效的数据结构如位图来进一步优化查找性能。
  4. 减少系统调用:在用户态缓存一些共享内存状态信息,尽量减少对sem_waitsem_post等系统调用的次数,提高整体效率。