linux 共享内存

共享内存是最高效的IPC机制,因为它不涉及进程之间的任何数据传输。这种高效带来的问题是,我们必须用其他手段来同步进程对共享内存的访问,否则会产生竞态条件。所以,共享内存通常和其他进程间通信方式一起使用。

linux 共享内存有四个系统调用:shmget, shmat, shmdt, shmctl

shmget

创建一段新的共享内存,或者获取一段已经存在的共享内存:

       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmget(key_t key, size_t size, int shmflg);

key 是一个键值,用来标识一段全局唯一的共享内存。size 指定内存的大小,单位是字节。如果是创建内存,size必须指定,如果是获取已经存在的内存,size 可以设置为0

shmflg 和 semget的 semflg 参数相同。

shmget成功时返回一个正整数,它是共享内存的标识符。失败时返回-1,并设置errno.

shmat

共享内存被创建/获取之后,并不能立即访问它,而是需要先将它关联到进程的地址空间中。使用shmat函数:

void *shmat(int shmid, const void *shmaddr, int shmflg)

shmid 参数是有shmget函数返回的标识符。shmaddr指定将共享内存关联到进程的哪块地址空间,如果为NULL,则被关联地址由操作系统选择。

成功时,返回共享内存被关联到的地址,失败则返回(void*)-1,并设置errno

shmdt

int shmdt(const void *shmaddr);

将关联的共享内存从进程分离。

成功返回0,失败返回-1,并设置errno

shmctl

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

shmid 使用shmget返回的共享内存标识符。cmd指定执行的命令,常用的 IPC_RMID,表示将共享内存打上删除的标记,当最后一个使用它的进程调用shmdt将它从进程中分离时,该共享内存就被删除了。

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

union semun
{
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                               (Linux-specific) */
};

void ErrExit(const char* reason)
{
    fprintf(stderr, "%s: %d, %s\n", reason, errno, strerror(errno));
    exit(1);
}

int initsem(int key = 0)
{
    int semid = -1;

    if (-1 == (semid = semget(key, 1, 0666 | IPC_CREAT)))
    {
        ErrExit("semget");
    }

    union semun un;
    un.val = 2;
    if (-1 == semctl(semid, 0, SETVAL, un))
    {
        ErrExit("semctl");
    }

    return semid;
}

void destroysem(int semid)
{
    if (-1 == semctl(semid, 0, IPC_RMID))
    {
        ErrExit("semctl del");
    }
}

void P(int semid)
{
    struct sembuf op;
    op.sem_num = 0;
    op.sem_op = -1;
    op.sem_flg = SEM_UNDO;
    if (-1 == semop(semid, &op, 1))
    {
        ErrExit("semop p");
    }
}

void V(int semid)
{
    struct sembuf op;
    op.sem_num = 0;
    op.sem_op = 1;
    op.sem_flg = SEM_UNDO;
    if (-1 == semop(semid, &op, 1))
    {
        ErrExit("semop v");
    }
}

void waitfor0(int semid)
{
    struct sembuf op;
    op.sem_num = 0;
    op.sem_op = 0;
    op.sem_flg = SEM_UNDO;
    if (-1 == semop(semid, &op, 1))
    {
        ErrExit("semop wait");
    }
}



int main(int argc, char const *argv[])
{
    int semid = initsem();
    int shmid = -1;

    int pipefd[2];

    // 管道用来传递 共享内存id
    pipe(pipefd);

    pid_t pid = fork();
    if (pid > 0)
    {
        P(semid);
        close(pipefd[0]);
        printf("parent process...\n");

        shmid = shmget(0, 1024, 0666 | IPC_CREAT);
        if (-1 == shmid)
        {
            ErrExit("shmget");
        }

        write(pipefd[1], &shmid, 4);

        void* p = shmat(shmid, NULL, 0);
        if ((void*)-1 == p)
        {
            ErrExit("shmat");
        }

        char buf[60] = "data from parent";
        memcpy(p, buf, strlen(buf));

        printf("exit parent process...\n");
        P(semid);
        // P(semid);
        waitpid(pid, NULL, 0);

        destroysem(semid);
        if (-1 == shmctl(shmid, IPC_RMID, NULL))
        {
            ErrExit("shmctl");
        }
        if (-1 == shmdt(p))
        {
            ErrExit("shmdt in parent");
        }
    }
    else if (0 == pid)
    {
        // 等待共享内存集的值变为0
        waitfor0(semid);
        close(pipefd[1]);
        printf("child process...\n");

        read(pipefd[0], &shmid, 4);
        
        void* p = shmat(shmid, NULL, 0);
        if ((void*)-1 == p)
        {
            ErrExit("shmat");
        }

        char buf[60] = {0};
        memcpy(buf, p, 60);
        printf("%s\n", buf);

        if (-1 == shmdt(p))
        {
            ErrExit("shmdt in parent");
        }

        // V(semid);
    }


    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zuofaqi/p/9644204.html