69-Linux_共享内存

共享内存

  • 一.什么是共享内存
  • 二.共享内存的接口
    • 1.shmget
    • 2.shmat
    • 3.shmat
    • 4.shmctl
  • 三.例题
    • 1.进程 a 向共享内存中写入数据,进程 b 从共享内存中读取数据并显示
    • 2.进程 a 从键盘循环获取数据并拷贝到共享内存中,进程 b 从共享内存中获取并打印数据。要求进程 a 输入一次,进程 b 输出一次,进程 a 不输入,进程 b 也不输出。

一.什么是共享内存

共享内存是先在物理内存上申请一块空间,多个进程可以将其映射到自己的虚拟地址空间中。 所有进程都可以访问共享内存中的地址,就好像它们是由 malloc 分配的一样。如果某个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。由于它并未提供同步机制,所以我们通常需要用其他的机制来同步对共享内存的访问。
共享内存为多个进程之间共享和传递数据提供了一种有效的方式。
69-Linux_共享内存_第1张图片

二.共享内存的接口

1.shmget

int shmget(key_t key, size_t size, int shmflg);
shmget()用于创建或者获取共享内存
shmget()成功返回共享内存的 ID, 失败返回-1
key: 不同的进程使用相同的 key值可以获取到同一个共享内存,(注意:这里的值和信号量的值一样也没有关系,因为类型不一样;
size:
创建共享内存时,指定要申请的共享内存空间大小
shmflg: IPC_CREAT IPC_EXCL

2.shmat

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

shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上

shmat()成功返回返回共享内存的首地址,失败返回 NULL(像malloc一样给共享空间的起始地址),看帮助手册失败返回的是(void *)-1;
shmaddr:一般给 NULL,由系统自动选择映射的虚拟地址空间 shmflg: 一般给 0(给0就代表的可读写),可以给 SHM_RDONLY为只读模式,其他的为读写

3.shmat

int shmdt(const void *shmaddr);
shmdt()断开当前进程的 shmaddr 指向的共享内存映射
shmdt()成功返回 0, 失败返回-1

4.shmctl

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl()控制共享内存
shmctl()成功返回 0,失败返回-1
cmd: IPC_RMID

三.例题

1.进程 a 向共享内存中写入数据,进程 b 从共享内存中读取数据并显示

//main.c用于写入数据

#include
#include
#include
#include
#include
#include

int main()
{
    int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    assert(shmid!=-1);

    char* s=(char*)shmat(shmid,NULL,0);
    if(s==(char*)-1)
    {
        exit(1);
    }
    strcpy(s,"Hello");
    shmdt(s);
    exit(0);
}

//test.c 用于读取数据

#include
#include
#include
#include
#include
#include

int main()
{
    int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    assert(shmid!=-1);

    char* s=(char*)shmat(shmid,NULL,0);
    if(s==(char*)-1)
    {
        exit(1);
    }
    printf("%s\n",s);
    shmdt(s);


    shmctl(shmid,IPC_RMID,NULL);
    exit(0);
}

2.进程 a 从键盘循环获取数据并拷贝到共享内存中,进程 b 从共享内存中获取并打印数据。要求进程 a 输入一次,进程 b 输出一次,进程 a 不输入,进程 b 也不输出。

思路:
69-Linux_共享内存_第2张图片

//sem.h

#include
#include
#include

union semun
{
    int val;
};

void sem_init();
void sem_p(int index);
void sem_v(int index);
void sem_destroy();

//sem.c

#include"sem.h"

#define SEM_NUM 2
static int semid=-1;

void sem_init()//创建信号量,并初始化
{
    semid=semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);
    if(semid==-1)
    {
        semid=semget((key_t)1234,SEM_NUM,0600);
        if(semid==-1)
        {
            perror("semget error\n");
        }
    }
    else
    {
        int arr[SEM_NUM]={1,0};
        for(int i=0;i<SEM_NUM;i++)
        {
            //初始化
            union semun a;
            a.val=arr[i];
            if(semctl(semid,i,SETVAL,a)==-1)//全新创建成功,就初始化
            {
                perror("semctl init error");
            } 
        }     
    }
}

void sem_p(int index)//p操作
{
    if(index<0||index>=SEM_NUM)
    {
        return;
    }
    struct sembuf buf;
    buf.sem_num=index;
    buf.sem_op=-1;//p操作
    buf.sem_flg=SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("p errro\n");
    }
}

void sem_v(int index)
{
    if(index<0||index>=SEM_NUM)
    {
        return ;
    }
    struct sembuf buf;
    buf.sem_num=index;
    buf.sem_op=1;//v操作
    buf.sem_flg=SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("v error\n");
    }
}

void sem_destroy()
{
    if(semctl(semid,0,IPC_RMID)==-1)
    {
        perror(" destroy sem error\n");
    }
}

//a.c

#include
#include
#include
#include
#include
#include
#include"sem.h"

int main()
{
    int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    assert(shmid!=-1);

    char* s=(char*)shmat(shmid,NULL,0);
    if(s==(char*)-1)
    {
        exit(1);
    }

    sem_init();
    while(1)
    {
        printf("Input:");
        char buff[128]={0};
        fgets(buff,128,stdin);

        sem_p(0);
         strcpy(s,buff);
         sem_v(1);
         if(strncmp(buff,"end",3)==0)
         {
             break;
         }
    }

    shmdt(s);
    exit(0);
}

//b.c

#include
#include
#include
#include
#include
#include
#include"sem.h"

int main()
{
    int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    assert(shmid!=-1);

    char* s=(char*)shmat(shmid,NULL,0);
    if(s==(char*)-1)
    {
        exit(1);
    }
    
    sem_init();
    while(1)
    {
        sem_p(1);
        if(strncmp(s,"end",3)==0)
        {
            break;
        }
        printf("read:%s",s);
        sleep(1);
        sem_v(0);
    }
    shmdt(s);
    sem_destroy();

    shmctl(shmid,IPC_RMID,NULL);
    exit(0);
}

运行结果:
69-Linux_共享内存_第3张图片

你可能感兴趣的:(Linux,c++,开发语言,linux)