14-LINUX--共享内存

本文详细介绍了共享内存的工作原理,包括如何使用`shmget`、`shmat`和`shmdt`创建、链接和分离共享内存,以及如何使用信号量进行同步。通过C语言示例展示了如何在两个进程中共享数据并实现基本的同步操作。
摘要由CSDN通过智能技术生成

一.共享内存

1.原理:

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

2.相关函数

 1>.shmget : 创建共享内存

 2>.shmat : 将共享内存链接到进程

 3>.shmdt:将共享内存与进程分离

3.示例代码

 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/types.h>
 /*
     shmget()用于创建或者获取共享内存
     shmget()成功返回共享内存的 ID, 失败返回-1
     key: 不同的进程使用相同的 key 值可以获取到同一个共享内存
     size: 创建共享内存时,指定要申请的共享内存空间大小
     shmflg: IPC_CREAT IPC_EXCL
 */
 int shmget(key_t key, size_t size, int shmflg);
 /*
     shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上
     shmat()成功返回返回共享内存的首地址,失败返回 NULL
     shmaddr:一般给 NULL,由系统自动选择映射的虚拟地址空间
     shmflg: 一般给 0, 可以给 SHM_RDONLY 为只读模式,其他的为读写
 */
 void* shmat(int shmid, const void *shmaddr, int shmflg);
 /*
     shmdt()断开当前进程的 shmaddr 指向的共享内存映射
     shmdt()成功返回 0, 失败返回-1
 */
 int shmdt(const void *shmaddr);
 /*
     shmctl()控制共享内存
     shmctl()成功返回 0,失败返回-1
     cmd: IPC_RMID
 */
 int shmctl(int shmid, int cmd, struct shmid_ds *buf);

a.c

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

int main()
{
    int shmid = shmget((key_t)1234,128,IPC_CREAT|0600);
    if (shmid == -1 )
    {
        exit(1);
    }

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

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

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

b.c

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

int main()
{
    int shmid = shmget((key_t)1234,128,IPC_CREAT|0600);
    if (shmid == -1 )
    {
        exit(1);
    }

    char* s = (char*)shmat(shmid,NULL,0);
    if (s == (char*)-1 )
    {
        exit(1);
    }
    sem_init();
    while(1 )
    {
        sem_p(1);//ps2
        if (strncmp(s,"end",3) == 0 )
        {
            break;
        }
        printf("s=%s\n",s);
        sem_v(0);//vs1
    }
    sem_destroy();
    shmdt(s);
    shmctl(shmid,IPC_RMID,NULL);
    exit(0);
}

sem.h

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

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"

static int semid = -1;
void sem_init()
{
    semid = semget((key_t)1234,2,IPC_CREAT|IPC_EXCL|0600);//全新创建
    if (semid == -1 )//全新创建失败,那么直接获取已存在的信号量的id
    {
        semid = semget((key_t)1234,2,IPC_CREAT|0600);
        if (semid == -1)
        {
            printf("semget err\n");
            return;
        }
    }
    else//全新创建成功,初始化
    {
        union semun a;
        int arr[2] = {1,0};
        for(int i = 0; i <2; i++ )
        {
            a.val = arr[i];
            if (semctl(semid,i,SETVAL,a) == -1 )
            {
                printf("semctl setval err\n");
            }
        }
    }
}
void sem_p(int index)
{
    struct sembuf buf;
    buf.sem_num = index;//信号量的下标,目前只有一个,所以为0
    buf.sem_op = -1;//p
    buf.sem_flg = SEM_UNDO;

    if ( semop(semid,&buf,1) == -1 )
    {
        printf("semop p err\n");
    }
}
void sem_v(int index)
{
    struct sembuf buf;
    buf.sem_num = index;//信号量的下标,目前只有一个,所以为0
    buf.sem_op = 1;//v
    buf.sem_flg = SEM_UNDO;

    if ( semop(semid,&buf,1) == -1 )
    {
        printf("semop v err\n");
    }

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

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

果蛋蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值