69天探索操作系统-第36天:共享内存

334 阅读6分钟

pro6.avif

1.介绍

共享内存是进程间通信(IPC)机制中最快的一种,因为它允许进程直接访问相同的内存区域。这消除了数据复制的需要,使其对于高性能应用来说非常高效。高级共享内存技术涉及底层内存管理、同步和优化策略。

image.png

关键概念:

  • 内存映射: 共享内存通常通过内存映射文件或匿名内存映射来实现。这使得进程能够将相同的物理内存映射到它们的地址空间。
  • 页面对齐: 内存以页面为单位进行管理(通常为4KB)。将数据结构对齐到页面边界可以提高性能并防止缓存行争用。
  • 内存保护: 可以使用标志如 PROT_READPROT_WRITEPROT_EXEC 来保护共享内存区域,以控制访问。
  • 缓存一致性: 确保所有进程在共享内存中看到一致的数据需要仔细处理缓存一致性。
  • 内存屏障: 这些用于强制内存操作的顺序,确保一个进程所做的更改以正确的顺序对其他进程可见。
  • 内存排序: 现代CPU可能会为了性能而对内存操作进行重排序。内存屏障和原子操作有助于保持正确的顺序。

2. 底层共享内存操作

2.1 POSIX 共享内存实现

以下代码演示了如何使用 POSIX 共享内存,并包含互斥同步等高级功能。

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

#define SHM_NAME "/advanced_shm"
#define SHM_SIZE 4096

typedef struct {
    int counter;
    char data[1024];
    pthread_mutex_t mutex;
} shared_data_t;

int main() {
    int fd;
    shared_data_t *shared_data;

    fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    if (fd == -1) {
        perror("shm_open");
        exit(EXIT_FAILURE);
    }

    if (ftruncate(fd, SHM_SIZE) == -1) {
        perror("ftruncate");
        exit(EXIT_FAILURE);
    }

    shared_data = mmap(NULL, SHM_SIZE,
                      PROT_READ | PROT_WRITE,
                      MAP_SHARED, fd, 0);
    if (shared_data == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&shared_data->mutex, &mutex_attr);

    shared_data->counter = 0;
    strcpy(shared_data->data, "Initial data");

    pthread_mutexattr_destroy(&mutex_attr);

    return 0;
}

运行代码:

gcc -o shm_advanced shm_advanced.c -lrt -lpthread
./shm_advanced

预期输出: 程序将创建一个共享内存段,并用计数器和字符串进行初始化。不会打印任何输出,但共享内存将可供其他进程使用。

3. 内存映射和保护

3.1 高级内存映射

以下代码演示了高级内存映射技术,包括内存对齐和保护。

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

#define PAGE_SIZE 4096

void *create_aligned_memory(size_t size) {
    void *addr;

    if (posix_memalign(&addr, PAGE_SIZE, size) != 0) {
        perror("posix_memalign");
        return NULL;
    }

    if (mlock(addr, size) == -1) {
        perror("mlock");
        free(addr);
        return NULL;
    }

    return addr;
}

int main() {
    void *aligned_mem = create_aligned_memory(PAGE_SIZE);
    if (!aligned_mem) {
        exit(EXIT_FAILURE);
    }

    void *mapped_mem = mmap(NULL, PAGE_SIZE,
                           PROT_READ | PROT_WRITE,
                           MAP_PRIVATE | MAP_ANONYMOUS,
                           -1, 0);
    if (mapped_mem == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    if (mprotect(mapped_mem, PAGE_SIZE, PROT_READ) == -1) {
        perror("mprotect");
        exit(EXIT_FAILURE);
    }

    munlock(aligned_mem, PAGE_SIZE);
    free(aligned_mem);
    munmap(mapped_mem, PAGE_SIZE);

    return 0;
}

4. 同步机制

4.1 高级互斥锁实现

以下代码演示了如何创建一个共享互斥锁和条件变量,用于进程之间的同步。

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

typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int flag;
} sync_struct_t;

sync_struct_t *create_sync_structure() {
    sync_struct_t *sync;

    sync = mmap(NULL, sizeof(sync_struct_t),
                PROT_READ | PROT_WRITE,
                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (sync == MAP_FAILED) {
        perror("mmap");
        return NULL;
    }

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&sync->mutex, &mutex_attr);

    pthread_condattr_t cond_attr;
    pthread_condattr_init(&cond_attr);
    pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&sync->cond, &cond_attr);

    sync->flag = 0;

    pthread_mutexattr_destroy(&mutex_attr);
    pthread_condattr_destroy(&cond_attr);

    return sync;
}

运行代码:

gcc -o sync_advanced sync_advanced.c -lpthread
./sync_advanced

预期输出: 该程序将创建一个带有互斥锁和条件变量的共享同步结构。不会打印任何输出,但该结构将可供其他进程使用。

5. 高级内存管理

5.1 自定义内存分配器

以下代码演示了如何使用共享内存创建自定义内存分配器。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>

#define POOL_SIZE (1024 * 1024)  // 1MB pool

typedef struct memory_block {
    size_t size;
    int free;
    struct memory_block *next;
} memory_block_t;

typedef struct {
    void *pool;
    memory_block_t *first_block;
} memory_pool_t;

memory_pool_t *create_memory_pool() {
    memory_pool_t *pool = malloc(sizeof(memory_pool_t));
    if (!pool) return NULL;

    pool->pool = mmap(NULL, POOL_SIZE,
                     PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS,
                     -1, 0);
    if (pool->pool == MAP_FAILED) {
        free(pool);
        return NULL;
    }

    pool->first_block = (memory_block_t*)pool->pool;
    pool->first_block->size = POOL_SIZE - sizeof(memory_block_t);
    pool->first_block->free = 1;
    pool->first_block->next = NULL;

    return pool;
}

void *pool_alloc(memory_pool_t *pool, size_t size) {
    memory_block_t *current = pool->first_block;
    memory_block_t *best_fit = NULL;
    size_t min_size_diff = SIZE_MAX;

    while (current) {
        if (current->free && current->size >= size) {
            size_t size_diff = current->size - size;
            if (size_diff < min_size_diff) {
                min_size_diff = size_diff;
                best_fit = current;
            }
        }
        current = current->next;
    }

    if (!best_fit) return NULL;

    if (best_fit->size > size + sizeof(memory_block_t) + 32) {
        memory_block_t *new_block = (memory_block_t*)((char*)best_fit +
                                   sizeof(memory_block_t) + size);
        new_block->size = best_fit->size - size - sizeof(memory_block_t);
        new_block->free = 1;
        new_block->next = best_fit->next;

        best_fit->size = size;
        best_fit->next = new_block;
    }

    best_fit->free = 0;
    return (char*)best_fit + sizeof(memory_block_t);
}

6. 性能优化

6.1 内存对齐和缓存优化

以下代码演示了如何优化内存访问模式以获得更好的缓存性能。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define CACHE_LINE 64

typedef struct __attribute__((aligned(CACHE_LINE))) {
    int64_t data;
    char padding[CACHE_LINE - sizeof(int64_t)];
} aligned_data_t;

void optimize_access(aligned_data_t *data, size_t size) {
    for (size_t i = 0; i < size; i += CACHE_LINE) {
        data[i].data = i;
    }
}

7. 实现示例

7.1 带同步的共享内存

以下代码演示了如何使用互斥锁和条件变量等同步机制来使用共享内存。

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

typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int flag;
} sync_struct_t;

sync_struct_t *create_sync_structure() {
    sync_struct_t *sync;

    sync = mmap(NULL, sizeof(sync_struct_t),
                PROT_READ | PROT_WRITE,
                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (sync == MAP_FAILED) {
        perror("mmap");
        return NULL;
    }

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&sync->mutex, &mutex_attr);

    pthread_condattr_t cond_attr;
    pthread_condattr_init(&cond_attr);
    pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&sync->cond, &cond_attr);

    sync->flag = 0;

    pthread_mutexattr_destroy(&mutex_attr);
    pthread_condattr_destroy(&cond_attr);

    return sync;
}

运行代码:

gcc -o shm_sync_example shm_sync_example.c -lpthread
./shm_sync_example

预期输出: 该程序将创建一个带有互斥锁和条件变量的共享同步结构。不会打印任何输出,但该结构将可供其他进程使用。

8. 安全考虑

8.1 内存保护

内存保护对于确保共享内存的安全性至关重要。以下代码演示了如何使用mprotect设置内存保护。

if (mprotect(addr, size, PROT_READ | PROT_WRITE) == -1) {
    perror("mprotect");
    exit(EXIT_FAILURE);
}

8.2 访问控制

访问控制确保只有授权的进程才能访问共享内存。以下代码演示了如何为共享内存设置适当的权限。

mode_t mode = S_IRUSR | S_IWUSR;
int fd = shm_open(name, O_CREAT | O_RDWR, mode);

9. 调试技术

9.1 内存转储工具 以下代码演示了一个用于转储内存内容的工具,这对于调试共享内存问题非常有用。

#include <stdio.h>
#include <sys/mman.h>

void dump_memory_info(void *addr, size_t size) {
    unsigned char *ptr = (unsigned char*)addr;
    printf("Memory dump at %p:\n", addr);

    for (size_t i = 0; i < size; i++) {
        if (i % 16 == 0) printf("\n%04zx: ", i);
        printf("%02x ", ptr[i]);
    }
    printf("\n");
}

10. 总结

高级共享内存编程需要深入了解内存管理、同步和系统架构。这里介绍的技术为构建高效共享进程间数据的高性能应用程序奠定了基础。