IPC通信_共享内存

Posted ho966

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
");
        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
");
    }        
}   
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
");
        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
");
        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
");  
        return -1; 
    }  
    //将共享内存连接到当前进程的地址空间  
    char* buf = (char*)shmat(shmid, (void*)0, 0);  
    if(buf == (void*)-1)  
    {  
        printf("shmget failed
");  
        return -1;  
    }  
    printf("Memory attached at %p
", 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
");  
        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
");
        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
");
    }        
}   
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
");
        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
");
        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
");  
        return -1; 
    }  
    //将共享内存连接到当前进程的地址空间  
    char* buf = (char*)shmat(shmid, (void*)0, 0);  
    if(buf == (void*)-1)  
    {  
        printf("shmget failed
");  
        return -1;  
    }  
    printf("Memory attached at %p
", buf);
    while(1)
    {   
        semaphore_p(sem_id);//信号量P操作
        printf("read buf:%s
",buf);   

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

 

以上是关于IPC通信_共享内存的主要内容,如果未能解决你的问题,请参考以下文章

Linux进程IPC浅析[进程间通信SystemV共享内存]

Linux进程IPC浅析[进程间通信SystemV共享内存]

使用 IPC 共享内存的应用程序可以访问彼此的代码吗?

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

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

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