MST
星途 面试题库

面试题:C语言Linux多线程与内存映射的数据共享

在Linux系统中,利用C语言实现多线程通过内存映射进行数据共享。假设有两个线程,一个线程往内存映射区域写入数据,另一个线程从该区域读取数据。请描述如何确保数据的一致性和线程安全,包括但不限于使用互斥锁、信号量等机制,同时给出关键代码片段。
24.3万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

确保数据一致性和线程安全的方法

  1. 互斥锁(Mutex):互斥锁是一种简单的同步机制,用于保证在同一时间只有一个线程可以访问共享资源。在这个场景中,共享资源就是内存映射区域。在写入或读取数据前,线程需要先获取互斥锁,操作完成后释放互斥锁。
  2. 信号量(Semaphore):信号量可以用来控制同时访问共享资源的线程数量。在本场景中,可以使用二元信号量(本质类似互斥锁)来确保只有一个线程能访问内存映射区域。信号量还可以用于线程间的同步,比如在写入线程完成数据写入后,通过信号量通知读取线程数据已准备好。

关键代码片段

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

#define SHM_SIZE 1024

// 定义共享数据结构
typedef struct {
    int data;
} SharedData;

SharedData *shared_mem;
sem_t *semaphore;
pthread_mutex_t mutex;

// 写入线程函数
void* write_thread(void* arg) {
    for (int i = 0; i < 5; i++) {
        // 获取互斥锁
        pthread_mutex_lock(&mutex);
        shared_mem->data = i;
        printf("Write thread: wrote data %d\n", shared_mem->data);
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);
        // 发送信号量通知读取线程数据已更新
        sem_post(semaphore);
        sleep(1);
    }
    return NULL;
}

// 读取线程函数
void* read_thread(void* arg) {
    for (int i = 0; i < 5; i++) {
        // 等待信号量,确保有新数据可读取
        sem_wait(semaphore);
        // 获取互斥锁
        pthread_mutex_lock(&mutex);
        printf("Read thread: read data %d\n", shared_mem->data);
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    return NULL;
}

int main() {
    int shm_fd;

    // 创建共享内存对象
    shm_fd = shm_open("/shared_memory", O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) {
        perror("shm_open");
        return 1;
    }

    // 配置共享内存大小
    if (ftruncate(shm_fd, SHM_SIZE) == -1) {
        perror("ftruncate");
        return 1;
    }

    // 内存映射
    shared_mem = (SharedData*)mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_mem == MAP_FAILED) {
        perror("mmap");
        return 1;
    }

    // 初始化信号量
    semaphore = sem_open("/semaphore", O_CREAT, 0666, 0);
    if (semaphore == SEM_FAILED) {
        perror("sem_open");
        return 1;
    }

    // 初始化互斥锁
    if (pthread_mutex_init(&mutex, NULL) != 0) {
        perror("pthread_mutex_init");
        return 1;
    }

    pthread_t write_tid, read_tid;

    // 创建写入线程
    if (pthread_create(&write_tid, NULL, write_thread, NULL) != 0) {
        perror("pthread_create write_thread");
        return 1;
    }

    // 创建读取线程
    if (pthread_create(&read_tid, NULL, read_thread, NULL) != 0) {
        perror("pthread_create read_thread");
        return 1;
    }

    // 等待线程结束
    pthread_join(write_tid, NULL);
    pthread_join(read_tid, NULL);

    // 解除内存映射
    if (munmap(shared_mem, SHM_SIZE) == -1) {
        perror("munmap");
        return 1;
    }

    // 关闭共享内存对象
    if (close(shm_fd) == -1) {
        perror("close");
        return 1;
    }

    // 删除共享内存对象
    if (shm_unlink("/shared_memory") == -1) {
        perror("shm_unlink");
        return 1;
    }

    // 销毁信号量
    if (sem_close(semaphore) == -1) {
        perror("sem_close");
        return 1;
    }
    if (sem_unlink("/semaphore") == -1) {
        perror("sem_unlink");
        return 1;
    }

    // 销毁互斥锁
    if (pthread_mutex_destroy(&mutex) != 0) {
        perror("pthread_mutex_destroy");
        return 1;
    }

    return 0;
}

以上代码展示了如何使用互斥锁和信号量在多线程间通过内存映射实现数据共享,并确保数据的一致性和线程安全。