Linux进程间通信之共享内存

Ilovewuhandefengjing 2011-12-05 10:37:32
Linux进程间通信之共享内存

作者:武汉华嵌技术部



共享内存区是可用IPC形式中最快的。一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传递就不再涉及内核(这里说的不涉及内核的含义是:进程不再通过执行任何进入内核的系统调用来彼此传递数据)。然而往该共享内存区存放信息或从中取走信息的进程间通常需要某种形式的同步,同步的方式有多种,比如:信号量、互斥锁等等。





以下两图分别描述了读写消息时,一个要进入内核,而一个不进入内核的情况:





对于System V共享内存区,内核维护如下的信息结构,它定义在<sys/shm.h>头文件中:

struct shmid_ds{

struct ipc_perm shm_perm; /* operation permission struct */

size_t shm_segsz; /* segment size */

.

.

.

};



有了以上的知识,那么如何来对共享内存进行操作呢,以下就开始讲解如何来操作:

创建一个新的共享内存区,或者访问一个已存在的共享内存区。
#include <sys/shm.h>

int shmget(key_t key, size_t size, into flag);

size以字节为单位指定内存区的大小。当实际操作为创建一个新的共享内存区时,必须指定一个不为0的size值。如果实际操作为访问一个已存在的共享内存区,那么size应为0。

oflag为读写权限值的组合。它还可以与IPC_CREAT或IPC_CREAT|IPC_EXCL按位或。

当实际操作为创建一个共享内存区时,该内存区被初始化为size字节的0。

由shmget创建或打开一个共享内存区后,通过调用shmat把它附接到调用进程的地址空间。
#include <sys/shm.h>

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

shmid是由shmget返回的标识符。Shmat的返回值是所指定的共享内存区在调用进程内的起始地址。确定这个地址的规则如下:

如果shmaddr是一个空指针,那么系统替调用者选择地址。(这个是推荐的方法)
如果shmaddr是一个非空指针,那么返回地址取决于调用者是否给flag参数指定了SHM_RND:
如果没有指定SHM_RND,那么相应的共享内存区附接到由shmaddr参数指定的地址;
如果指定了SHM_RND,那么相应的共享内存区附接到由shmaddr参数指定的地址向下舍入一个SHMLBA常值。
当一个进程完成共享内存区的使用时,它可调用shmdt断接这个内存区。
#include <sys/shm.h>

int shmdt(const void *shmaddr);

当一个进程终止时,它当前附接着的所有共享内存区都自动断接掉。

注意:本函数调用并不删除所指定的共享内存区。

shmctl提供了对一个共享内存区的多种操作。
#icnldue <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buff);

该函数提供了三个命令:

IPC_RMID 从系统中删除由shmid标识的共享内存区并拆除它。

IPC_SET 给所描写的共享内存区设置其shmid_ds结构的某些成员。

IPC_STAT 向调用者返回所指定共享内存区当前的shmid_ds结构。



以下是共享内存结合信号量进行操作的部份代码:



发关进程的部份代码:
//创建一个共享内存区

if((shmid1 = shmget(shmkey1, MAX_SHEARE_MEM_SIZE, IPC_CREAT|0666)) < 0)

{

perror("shmget");

}

//把共享内存区附接到调用进程的地址空间

if((sharmem = shmat(shmid1, NULL, 0)) < 0)

{

perror("shmat");

}



while(1)

{

sem_p(semid1); //semid1进行p操作,保护共享区

memset(buff, 0, MAX_SHEARE_MEM_SIZE);

printf("Input ou want to say with you friend!\n");

fgets(buff, MAX_SHEARE_MEM_SIZE, stdin);

if(strncmp(buff, "quit", 4))

{

//往共享内存区放入数据

strncpy(sharmem, buff, MAX_SHEARE_MEM_SIZE);

sem_v(semid2); //semid2进行v操作,释放对共享区的保护

}

else

{

strncpy(sharmem, buff, MAX_SHEARE_MEM_SIZE);

sem_v(semid2);

break;

}

}

接收进程部份代码:
while(1)

{

sem_p(semid2); //semid2进行p操作,保护共享区

memset(buff, 0, MAX_SHEARE_MEM_SIZE);

strncpy(buff, sharmem, MAX_SHEARE_MEM_SIZE); //从共享内存区取出数据

printf("receive from you friend : %s\n", buff);

if(!strncmp(buff, "quit", 4))

{

del_sem(semid1);

del_sem(semid2);

break;

}

sem_v(semid1); //semid1进行v操作,释放对共享区的保护

}

//删除共享内存区

if((shmctl(shmid1, IPC_RMID, NULL)) < 0)

{

perror("shmctl");

}



更多技术文章敬请关注:武汉华嵌-嵌入式培训专家,国内领先的嵌入式服务机构,

http://www.embedhq.org
...全文
563 回复 打赏 收藏 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
源码下载地址: https://pan.quark.cn/s/07e7935aff27 在Android应用开发过程中,`ImageView`作为一个基础组件被广泛运用,其主要功能是展示各种图像资源,这些资源可以来源于本地存储或通过网络获取。本文将详细阐述如何动态地变更`ImageView`所显示的图片内容,并借助自定义监听机制来监控和干预图片的加载流程。此类技术在应用开发中具有很高的实用价值,特别是在处理网络用户头像、商品展示图以及实时数据更新的场景下。 我们首先需要明确`ImageView`的基本操作方式。在Android平台,我们常通过`setImageResource()`、`setImageBitmap()`以及`setImageDrawable()`等函数来设定`ImageView`的图像内容。然而,这些方法主要适用于已加载至内存中的图像文件,对于网络图片,则需要借助更为复杂的处理逻辑。 在实现动态下载并更新`ImageView`中的图像时,我们普遍采用`AsyncTask`或`Loader`来执行后台任务,以此防止主线程被阻塞。本文将重点介绍自定义监听器的构建方法。自定义监听器能够让我们依据图片加载的进程或状态来执行特定的任务,例如显示加载进度指示器或处理加载失败的情况。 自定义监听器通常定义为一个接口,其中包含了若干个回调方法,例如`onStart()`、`onProgressUpdate()`、`onSuccess()`、`onError()`等。以下是一个示例接口定义: ```java public interface ImageDownloaderListener { void onStart(); void onProgress(int ...

18,828

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 专题技术讨论区
社区管理员
  • 专题技术讨论区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧