linux进程间通信-共享内存_Linux进程间通信

共享内存是一种进程间通信(IPC)机制,它允许两个或多个进程共享一个给定的存储区。因为数据直接映射到进程的地址空间,所以共享内存是最快的IPC形式之一。然而,由于共享内存不提供数据保护机制,所以需要使用信号量等同步机制来避免竞态条件。

共享内存的特点:

  1. 最快:由于避免了数据复制,共享内存是最快的IPC方法。
  2. 无同步机制:需要外部同步机制来保护共享数据。
  3. 生命周期:共享内存的生命周期与内核一致,除非显式删除。

共享内存的操作步骤:

  1. 创建共享内存:使用 shmget() 函数创建一块共享内存。
  2. 附加共享内存:使用 shmat() 函数将共享内存附加到进程地址空间。
  3. 读写共享内存:进程可以直接读写共享内存中的数据。
  4. 分离共享内存:使用 shmdt() 函数将共享内存从进程地址空间分离。
  5. 控制共享内存:使用 shmctl() 函数对共享内存进行控制,如删除共享内存。

共享内存的相关函数:

  • shmget(int key, size_t size, int shmflg):创建或获取共享内存段。
  • shmat(int shmid, const void *shmaddr, int shmflg):将共享内存段附加到调用进程的地址空间。
  • shmdt(const void *shmaddr):将共享内存段从调用进程的地址空间分离。
  • shmctl(int shmid, int cmd, struct shmid_ds *buf):对共享内存段进行控制操作。

进程间通信-共享内存实验

#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define SHM_SIZE 1024

int produce() {
    key_t key_shm = ftok(".", 'a');
    key_t key_sem = ftok(".", 'b');

    int shmid = shmget(key_shm, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid < 0) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    char *shmaddr = (char *)shmat(shmid, NULL, 0);
    if (shmaddr == (char *)(-1)) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    int semid = semget(key_sem, 1, IPC_CREAT | 0666);
    if (semid < 0) {
        perror("semget failed");
        exit(EXIT_FAILURE);
    }
    // 初始化信号量值为 1  
    if (semctl(semid, 0, SETVAL, 1) == -1) {  
        perror("semctl SETVAL failed");  
        exit(EXIT_FAILURE);  
    }  
    struct sembuf p_op = {0, -1, 0}; // P 操作
    struct sembuf v_op = {0, 1, 0};  // V 操作

    // 写入数据
    int cnt = 0;
    while (1) {
        semop(semid, &p_op, 1); // 等待信号量
        sprintf(shmaddr, "Hello from producer cnt = %d!", cnt);
        semop(semid, &v_op, 1); // 信号量释放
        printf("Produced: >> %s\n", shmaddr);
        sleep(1);
        cnt ++;
    }

    // 分离和删除共享内存和信号量
    shmdt(shmaddr);
    shmctl(shmid, IPC_RMID, NULL);
    semctl(semid, 0, IPC_RMID);

    return 0;
}

int consume() {
    key_t key_shm = ftok(".", 'a');
    key_t key_sem = ftok(".", 'b');
    int shmid = shmget(key_shm, SHM_SIZE, 0666);
    if (shmid < 0) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    char *shmaddr = (char *)shmat(shmid, NULL, 0);
    if (shmaddr == (char *)(-1)) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    int semid = semget(key_sem, 1, 0666);
    if (semid < 0) {
        perror("semget failed");
        exit(EXIT_FAILURE);
    }

    struct sembuf p_op = {0, -1, 0}; // P 操作
    struct sembuf v_op = {0, 1, 0};  // V 操作

    // 读取数据
    while (1) {
        semop(semid, &p_op, 1); // 等待信号量
        printf("Consumed: << %s\n", shmaddr);
        semop(semid, &v_op, 1); // 信号量释放
        sleep(1);
    }

    // 分离和删除共享内存和信号量
    shmdt(shmaddr);
    shmctl(shmid, IPC_RMID, NULL);
    semctl(semid, 0, IPC_RMID);

    return 0;
}

int main() {
    pid_t pid1, pid2;

    // 创建两个子进程
    pid1 = fork();
    if (pid1 < 0) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }

    if (pid1 == 0) {
        // 子进程 1:生产者
        produce();
    } else {
        pid2 = fork();
        if (pid2 < 0) {
            perror("fork failed");
            exit(EXIT_FAILURE);
        }

        if (pid2 == 0) {
            // 子进程 2:消费者
            consume();
        } else {
            // 父进程等待两个子进程结束
            int status;
            waitpid(pid1, &status, 0);
            waitpid(pid2, &status, 0);
        }
    }

    return 0;
}

进程间通信-共享内存实验结果

linux进程间通信-共享内存_共享内存_02