IPC通信_共享内存

共享内存允许两个或多个进程共享一个给定的存储区,就是多个进程将同一块物理内存映射到自己的虚拟地址上。因为不需要在客户进程和服务进程之间拷贝,所以是最快的一种IPC。

函数1

#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);

  该函数转换键值获取共享内存ID, key键值的获取还是通过ftok函数。

返回值:成功返回共享内存ID, 失败返回-1

参数key:键值(key)

参数size:请求的共享内存的长度,单位字节,如果引用一个现存在的段,将size置为0

参数flag:设置的权限,可参考消息队列。

函数2

#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  该函数对共享内存执行多种操作。

返回值:成功返回0,失败返回-1

参数shmid:共享内存ID

参数cmd:见下表


cmd参数


释意


IPC_STAT


参考消息队列


IPC_SET


参考消息队列


IPC_RMID


参考消息队列


SHM_LOCK


在内存中对共享存储段加锁,此命令只能由超级用户执行


SHM_UNLOCK


解锁共享存储段。此命令只能由超级用户执行

函数3

#include <sys/shm.h>
void *shmat(int shmid, const void *addr, int flag);

调用该函数将共享内存段连接到该进程的虚拟地址空间中

返回值: 成功返回共享内存段的指针,失败返回-1

参数shmid: 共享内存的ID

参数addr: 推荐为0,此时申请的共享内存连接到内核选择的一个可用地址上。

   如果非0,并且没有指定SHM_RND,则连接到addr所指定地址

   如果非0,且指定了SHM_RND,则连接到(addr-(addr mod SHMLBA))所表示的地址

参数flag:如果置位 SHM_RDONLY,则以只读方式连接,否则以读写方式连接此段

函数4

#include <sys/shm.h>
void *shmdt( const void *addr);

当对共享内存段的操作结束时,调用该函数与共享内存段分离。注意,这并不是从系统中删除其表示符以及相关数据结构,标识符依旧存在,直至某个进程带IPC_RMID命令的调用shmctl特地的删除为止。

返回值  :成功返回0,失败返回-1

参数addr:之前调用shmat的返回值

举例:

两个进程通过共享内存实现一个读,一个写,利用信号量实现同步

shmwrite.cpp

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <string.h>
#include <iostream>
#define BUFSIZE 128
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
};
int set_semvalue(int sem_id, int count)
{//用于初始化信号量,在使用信号量前必须这样做
    union semun sem_union;
    sem_union.val = count;
    if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
    {
        printf("set_semvalue failed\n");
        return -1;
    }
    return 0;
}
void del_semvalue(int sem_id)
{//删除信号量
    union semun sem_union;
    if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
    {
        printf("del_semvalue failed\n");
    }
}
int semaphore_p(int sem_id)
{//对信号量做减1操作,即等待P(sv)
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;//P()
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id, &sem_b, 1) == -1)
    {
        printf("semaphore_p failed\n");
        return -1;
    }
    return 0;
}
int semaphore_v(int sem_id)
{//这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;//V()
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id, &sem_b, 1) == -1)
    {
        printf("semaphore_v failed\n");
        return -1;
    }
    return 0;
}
int main(void)
{
    //创建信号量
    int sem_id = semget((key_t)4321, 1, 0666 | IPC_CREAT);
    set_semvalue(sem_id, 0);

    //创建共享内存
    int shmid = shmget((key_t)1234, BUFSIZE, 0666|IPC_CREAT);
    if(shmid == -1)
    {
        printf("shmget failed\n");
        return -1;
    }
    //将共享内存连接到当前进程的地址空间
    char* buf = (char*)shmat(shmid, (void*)0, 0);
    if(buf == (void*)-1)
    {
        printf("shmget failed\n");
        return -1;
    }
    printf("Memory attached at %p\n", buf);
    std::string str;

    while(std::cin>>str)//向共享内存中写数据
    {
        //输入了end,退出循环(程序)
        if(str == "end")  break;
        memset(buf,0,BUFSIZE);
        strncpy(buf, str.c_str(), BUFSIZE);
        semaphore_v(sem_id);//信号量V操作
    }
    //把共享内存从当前进程中分离
    if(shmdt(buf) == -1)
    {
        printf("shmdt failed\n");
        return -1;
    }
    shmctl(shmid,IPC_RMID,NULL);//删除共享内存
    del_semvalue(sem_id); //删除信号量
    return 0;
}

shmread.cpp

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <string.h>
#include <iostream>
#define BUFSIZE 128
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
};
int set_semvalue(int sem_id, int count)
{//用于初始化信号量,在使用信号量前必须这样做
    union semun sem_union;
    sem_union.val = count;
    if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
    {
        printf("set_semvalue failed\n");
        return -1;
    }
    return 0;
}
void del_semvalue(int sem_id)
{//删除信号量
    union semun sem_union;
    if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
    {
        printf("del_semvalue failed\n");
    }
}
int semaphore_p(int sem_id)
{//对信号量做减1操作,即等待P(sv)
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;//P()
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id, &sem_b, 1) == -1)
    {
        printf("semaphore_p failed\n");
        return -1;
    }
    return 0;
}
int semaphore_v(int sem_id)
{//这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;//V()
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id, &sem_b, 1) == -1)
    {
        printf("semaphore_v failed\n");
        return -1;
    }
    return 0;
}
int main(void)
{
    //获取信号量
    int sem_id = semget((key_t)4321, 1, 0666 | IPC_CREAT);      

    //获取共享内存
    int shmid = shmget((key_t)1234, 0, 0666|IPC_CREAT);
    if(shmid == -1)
    {
        printf("shmget failed\n");
        return -1;
    }
    //将共享内存连接到当前进程的地址空间
    char* buf = (char*)shmat(shmid, (void*)0, 0);
    if(buf == (void*)-1)
    {
        printf("shmget failed\n");
        return -1;
    }
    printf("Memory attached at %p\n", buf);
    while(1)
    {
        semaphore_p(sem_id);//信号量P操作
        printf("read buf:%s\n",buf);   

    }
    //把共享内存从当前进程中分离
    if(shmdt(buf) == -1)
    {
        printf("shmdt failed\n");
        return -1;
    }
    del_semvalue(sem_id); //删除信号量
    return 0;
}

原文地址:https://www.cnblogs.com/ho966/p/12261989.html

时间: 2024-10-10 06:43:52

IPC通信_共享内存的相关文章

域套接字通信域共享内存通信性能比较

最近碰到一个问题,两个进程间需要实时交换一些数据,数据量不是很大,就72个字节.当时估计简单起见,用的是域套接字的方式. 后续性能测试的时候,忽然发现当网络包并发量很大时,性能忽然大幅下降,用strace跟踪发现,忽然有好多的read,write操作,查看代码跟踪到此处,发现是域套接字需要不断的读写操作,虽然保证了数据的安全按序到达,但是此种操作性能太低.自己就想,两者究竟相差多少呢?跑两个程序比较下,一目了然.代码有些是用的网上现成的,水平有限,勿喷. 结果写在前面防止你看不到:域套接字跟共享

信号,信号量,锁,条件变量,消息通信,共享内存,RPC (一)

在实际项目当中,经常需要把一个功能分成多个子模块实现.那么,这些子模块之间该如何关联起来呢?静态地看,模块可以看作一组完成相同功能的函数:而动态地看,模块可以是一个独立的进程.线程或者一个中断服务或者信号服务例程.根据不同的具体业务实现,它们之间可能是静态调用.动态互斥.同步.唤醒等关系.静态的调用很好实现,上层的函数调用底层的函数即可.那么,动态互斥.同步.唤醒等关系,又该如何实现呢?这就设计到我们将要讨论的信号.进程间消息通信.共享内存.线程互斥同步条件变量.RPC等手段.下面就按照Linu

如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

不要通过共享内存来通信,而应该通过通信来共享内存 这是一句风靡golang社区的经典语,对于刚接触并发编程的人,该如何理解这句话? 如何理解"不要通过共享内存来通信,而应该通过通信来共享内存"? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/golang/1010000008937789/如何理解不要通过共享内存来通信而应该通过通信来共享内存.html

进程通信之共享内存

共享内存 共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自

IPC(SystemV) 之 共享内存

很久以来我都是只闻其名,未见其形.终于在这次系统的学习linux编程中接触到了共享内存.果然很牛. 上一篇文章中我们讲的信号量,个人感觉,严格的说,信号量只是进城通信的辅助.而共享内存才真正实现了进程通信. 共享内存机制允许两个不想关的进程访问同一段物理内存,当然得是一台主机. 头文件<sys/shm.h>   和信号量的情况一样,也需要包含sys/types.h 和 sys/ipc.h .当然有可能已经包含在了sys/shm.h中了. 共享内存函数如下: int shmget(key_t k

linux 进程通信之 共享内存

共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容. 关于共享内存使用的API key_t ftok(const char *pathname, int proj_id); #在IPC中,我们经常用一个 key_t 的值来创建或者打开 信号量,共享内存和消息队列.这个 key_t 就是由ftok函数产生的. pathname:指定的文件名,该文件必须是存在而且可以访问 proj_

进程间通信(IPC)之————共享内存

一. 共享内存 在系统中,两个不同的进程都会维护自己的一块地址空间,这个地址空间一般是虚拟地址,会通过mmu和页表映射到对应的物理内存中,因为不同的进程会有不同的内存空间,因此两个进程之间是无法看见彼此的数据的,而共享内存就是使两个进程看到同一块地址空间,以此来实现不同进程间的数据交互. 值得提出的是,共享内存是进程间通信方式中最高效的一种,因为是直接通过访问内存来交换数据的,省去了消息队列中数据的复制和信号量中进行P.V操作所占用的时间. 二. 共享内存中的函数 共享内存的创建与销毁 创建:

linux进程间的通信(C): 共享内存

一.共享内存介绍 共享内存是三个IPC(Inter-Process Communication)机制中的一个. 它允许两个不相关的进程访问同一个逻辑内存. 共享内存是在两个正在进行的进程之间传递数据的一种非常有效的方式. 大多数的共享内存的实现, 都把由不同进程之间共享的内存安排为同一段物理内存. 共享内存是由IPC为进程创建一个特殊的地址范围, 它将出现在该进程的地址空间中. 其他进程可以将同一段共享内存连接它们自己的地址空间中. 所有进程都可以访问共享内存中的地址, 就好像它们是由mallo

Linux IPC实践(8) --共享内存/内存映射

概述 共享内存区是最快的IPC形式.一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据(如图). 共享内存 VS. 其他IPC形式 用管道/消息队列传递数据 用共享内存传递数据 共享内存生成之后,传递数据并不需要再走Linux内核,共享内存允许两个或多个进程共享一个给定的存储区域,数据并不需要在多个进程之间进行复制,因此,共享内存的传输速度更快! mmap内存映射 将文件/设备空间映射到共享内存区 #incl