MST

星途 面试题库

面试题:C语言mmap在复杂场景下的应用

在一个多进程并发环境中,多个进程需要通过mmap共享同一个大文件进行读写操作,且要求保证数据一致性和操作的原子性。请用C语言设计一个完整的方案,阐述所涉及的数据结构、同步机制以及异常处理策略。
31.0万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

数据结构

  1. 共享内存结构体
typedef struct {
    // 假设大文件内容存储在此处,具体根据文件内容类型定义
    char data[LARGE_FILE_SIZE]; 
    // 用于同步操作的锁
    pthread_mutex_t mutex; 
} SharedData;

同步机制

  1. 互斥锁(Mutex)
    • 在共享内存结构体中定义一个pthread_mutex_t类型的互斥锁,如上述代码中的mutex
    • 在对共享文件数据进行读写操作前,使用pthread_mutex_lock(&shared_data->mutex)获取锁,操作完成后使用pthread_mutex_unlock(&shared_data->mutex)释放锁。
    • 示例代码片段:
SharedData *shared_data = (SharedData *)mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shared_data == MAP_FAILED) {
    perror("mmap");
    exit(EXIT_FAILURE);
}
// 初始化互斥锁
if (pthread_mutex_init(&shared_data->mutex, NULL) != 0) {
    perror("pthread_mutex_init");
    exit(EXIT_FAILURE);
}
// 读操作
pthread_mutex_lock(&shared_data->mutex);
// 进行读共享文件数据操作
pthread_mutex_unlock(&shared_data->mutex);
// 写操作
pthread_mutex_lock(&shared_data->mutex);
// 进行写共享文件数据操作
pthread_mutex_unlock(&shared_data->mutex);

异常处理策略

  1. mmap 错误
    • mmap函数返回MAP_FAILED时,使用perror打印错误信息,并根据情况选择退出程序或进行更复杂的错误恢复逻辑。如上述代码中:
if (shared_data == MAP_FAILED) {
    perror("mmap");
    exit(EXIT_FAILURE);
}
  1. 互斥锁操作错误
    • pthread_mutex_initpthread_mutex_lockpthread_mutex_unlock等函数返回非0值时,表示操作失败。同样使用perror打印错误信息,并根据情况处理。例如:
if (pthread_mutex_init(&shared_data->mutex, NULL) != 0) {
    perror("pthread_mutex_init");
    exit(EXIT_FAILURE);
}
  1. 文件操作错误
    • 在打开文件(假设使用open函数)时,如果返回 -1,表示打开文件失败,使用perror打印错误信息并处理。
int fd = open("large_file", O_RDWR);
if (fd == -1) {
    perror("open");
    exit(EXIT_FAILURE);
}
  1. munmap 错误
    • 在程序结束时,通常需要使用munmap解除映射,如果munmap返回 -1,表示解除映射失败,使用perror打印错误信息。
if (munmap(shared_data, sizeof(SharedData)) == -1) {
    perror("munmap");
    exit(EXIT_FAILURE);
}

完整示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <pthread.h>
#include <unistd.h>

#define LARGE_FILE_SIZE 1024 * 1024

typedef struct {
    char data[LARGE_FILE_SIZE];
    pthread_mutex_t mutex;
} SharedData;

int main() {
    int fd = open("large_file", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        perror("open");
        return EXIT_FAILURE;
    }
    if (lseek(fd, LARGE_FILE_SIZE - 1, SEEK_SET) == -1) {
        perror("lseek");
        close(fd);
        return EXIT_FAILURE;
    }
    if (write(fd, "", 1) != 1) {
        perror("write");
        close(fd);
        return EXIT_FAILURE;
    }

    SharedData *shared_data = (SharedData *)mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (shared_data == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return EXIT_FAILURE;
    }
    if (pthread_mutex_init(&shared_data->mutex, NULL) != 0) {
        perror("pthread_mutex_init");
        munmap(shared_data, sizeof(SharedData));
        close(fd);
        return EXIT_FAILURE;
    }

    // 示例进程操作
    // 读操作
    pthread_mutex_lock(&shared_data->mutex);
    // 进行读共享文件数据操作
    pthread_mutex_unlock(&shared_data->mutex);
    // 写操作
    pthread_mutex_lock(&shared_data->mutex);
    // 进行写共享文件数据操作
    pthread_mutex_unlock(&shared_data->mutex);

    if (pthread_mutex_destroy(&shared_data->mutex) != 0) {
        perror("pthread_mutex_destroy");
    }
    if (munmap(shared_data, sizeof(SharedData)) == -1) {
        perror("munmap");
    }
    close(fd);
    return 0;
}