Linux下使用能否使用C共享内存存放指针

Linux下使用能否使用C共享内存存放指针,第1张

共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存 (shared memory)是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。

共享内存的创建

共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统/proc目录下有对其描述的相应文件。函数shmget可以创建或打开一块共享内存区。函数原型如下: #include <sys/shm.h>int shmget( key_t key, size_t size, int flag )函数中参数key用来变换成一个标识符,而且每一个IPC对象与一个key相对应。当新建一个共享内存段时,size参数为要请求的内存长度(以字节为单位)。 注意:内核是以页为单位分配内存,当size参数的值不是系统内存页长的整数倍时,系统会分配给进程最小的可以满足size长的页数,但是最后一页的剩余部分内存是不可用的。 当打开一个内存段时,参数size的值为0。参数flag中的相应权限位初始化ipc_perm结构体中的mode域。同时参数flag是函数行为参数,它指定一些当函数遇到阻塞或其他情况时应做出的反应。shmid_ds结构初始化如表14-4所示。

编辑本段初始化

shmid_ds结构数据 初 值 shmid_ds结构数据 初 值

shm_lpid 0 shm_dtime 0

shm_nattach 0 shm_ctime 系统当前值

shm_atime 0 shm_segsz 参数 size

下面实例演示了使用shmget函数创建一块共享内存。程序中在调用shmget函数时指定key参数值为IPC_PRIVATE,这个参数的意义是创建一个新的共享内存区,当创建成功后使用shell命令ipcs来显示目前系统下共享内存的状态。命令参数-m为只显示共享内存的状态。 (1)在vi编辑器中编辑该程序如下: 程序清单14-8 create_shm.c 使用shmget函数创建共享内存 #include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdlib.h>#include <stdio.h>#define BUFSZ 4096 int main ( void ) printf ( "successfully created segment : %d \n", shm_id ) system( "ipcs -m")/*调用ipcs命令查看IPC*/ exit( 0 )} (2)在shell中编译该程序如下: $gcc create_shm.c–o create_shm (3)在shell中运行该程序如下: $./ create_shm successfully created segment : 2752516 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中使用shmget函数来创建一段共享内存,并在结束前调用了系统shell命令ipcs –m来查看当前系统IPC状态。

编辑本段共享内存的 *** 作

由于共享内存这一特殊的资源类型,使它不同于普通的文件,因此,系统需要为其提供专有的 *** 作函数,而这无疑增加了程序员开发的难度(需要记忆额外的专有函数)。使用函数shmctl可以对共享内存段进行多种 *** 作,其函数原型如下: #include <sys/shm.h>int shmctl( int shm_id, int cmd, struct shmid_ds *buf )函数中参数shm_id为所要 *** 作的共享内存段的标识符,struct shmid_ds型指针参数buf的作用与参数cmd的值相关,参数cmd指明了所要进行的 *** 作,其解释如表14-5所示。

编辑本段cmd参数详解

cmd的值 意 义

IPC_STAT 取shm_id所指向内存共享段的shmid_ds结构,对参数buf指向的结构赋值

IPC_SET 使用buf指向的结构对sh_mid段的相关结构赋值,只对以下几个域有作用,shm_perm. uid shm_perm.gid以及shm_perm.mode 注意此命令只有具备以下条件的进程才可以请求: 1.进程的用户ID等于shm_perm.cuid或者等于shm_perm.uid 2.超级用户特权进程

IPC_RMID 删除shm_id所指向的共享内存段,只有当shmid_ds结构的shm_nattch域为零时,才会真正执行删除命令,否则不会删除该段 注意此命令的请求规则与IPC_SET命令相同

SHM_LOCK 锁定共享内存段在内存,此命令只能由超级用户请求

SHM_UNLOCK 对共享内存段解锁,此命令只能由超级用户请求

使用函数shmat将一个存在的共享内存段连接到本进程空间,其函数原型如下: #include <sys/shm.h>void *shmat( int shm_id, const void *addr, int flag )函数中参数shm_id指定要引入的共享内存,参数addr与flag组合说明要引入的地址值,通常只有2种用法,addr为0,表明让内核来决定第1个可以引入的位置。addr非零,并且flag中指定SHM_RND,则此段引入到addr所指向的位置(此 *** 作不推荐使用,因为不会只对一种硬件上运行应用程序,为了程序的通用性推荐使用第1种方法),在flag参数中可以指定要引入的方式(读写方式指定)。 %说明:函数成功执行返回值为实际引入的地址,失败返回–1。shmat函数成功执行会将shm_id段的shmid_ds结构的shm_nattch计数器的值加1。 当对共享内存段 *** 作结束时,应调用shmdt函数,作用是将指定的共享内存段从当前进程空间中脱离出去。函数原型如下: #include <sys/shm.h>int shmdt( void *addr)参数addr是调用shmat函数的返回值,函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,失败返回–1。 下面实例演示了 *** 作共享内存段的流程。程序的开始部分先检测用户是否有输入,如出错则打印该命令的使用帮助。接下来从命令行读取将要引入的共享内存ID,使用shmat函数引入该共享内存,并在分离该内存之前睡眠3秒以方便查看系统IPC状态。 (1)在vi编辑器中编辑该程序如下: 程序清单14-9 opr_shm.c *** 作共享内存段 #include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdlib.h>#include <stdio.h>int main ( int argc, char *argv[] ) shm_id = atoi(argv[1])/*得到要引入的共享内存段*/ /*引入共享内存段,由内核选择要引入的位置*/ if ( (shm_buf = shmat( shm_id, 0, 0)) <(char *) 0 ) printf ( " segment attached at %p\n", shm_buf )/*输出导入的位置*/ system("ipcs -m")sleep(3)/* 休眠 */ if ( (shmdt(shm_buf)) <0 ) printf ( "segment detached \n" )system ( "ipcs -m " )/*再次查看系统IPC状态*/ exit ( 0 )} (2)在shell中编译该程序如下: $gcc opr_shm.c–o opr_shm (3)在shell中运行该程序如下: $./ opr_shm 2752516 segment attached at 0xb7f29000 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 1 segment detached ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中从命令行中读取所要引入的共享内存ID,并使用shmat函数引入该内存到当前的进程空间中。注意在使用shmat函数时,将参数addr的值设为0,所表达的意义是由内核来决定该共享内存在当前进程中的位置。由于在编程的过程中,很少会针对某一个特定的硬件或系统编程,所以由内核决定引入位置也就是shmat推荐的使用方式。在导入后使用shell命令ipcs –m来显示当前的系统IPC的状态,可以看出输出信息中nattch字段为该共享内存时的引用值,最后使用shmdt函数分离该共享内存并打印系统IPC的状态。

编辑本段共享内存使用注意事项

共享内存相比其他几种方式有着更方便的数据控制能力,数据在读写过程中会更透明。当成功导入一块共享内存后,它只是相当于一个字符串指针来指向一块内存,在当前进程下用户可以随意的访问。缺点是,数据写入进程或数据读出进程中,需要附加的数据结构控制,共享内存通信数据结构示意如图14-9所示。

编辑本段结构示意

%说明:图中两个进程同时遵循一定的规则来读写该内存。同时,在多进程同步或互斥上也需要附加的代码来辅助共享内存机制。 在共享内存段中都是以字符串的默认结束符为一条信息的结尾。每个进程在读写时都遵守这个规则,就不会破坏数据的完整性。

另外,站长团上有产品团购,便宜有保证

Linux属于 *** 作系统,docker属于容器

简单来说,docker是一个GO语言实现的基于LXC的用于开发应用、交付应用、运行应用的容器,除了docker以外,还有很多容器,比如Linux上的LXC、OpenVZ、FreeBSD的Jail、Solaris的Zones等。

看了上面的介绍,相信还是有很多小伙伴云里雾里的,docker相对来说不太好理解,docker的灵感来源于集装箱,在一艘大船上,可以把货物整齐摆放,且各式各样的货物被集装箱标准化了,彼此之间不会互相影响,也就不需要专门运送水果和专门运送化学品的了,只要这些货物在集装箱里封装好,就可以用一个交通工具把它们运走。

同理,docker就是这样的存在,云计算可以理解为交通工具,docker可以理解为集装箱。

虽说标准的硬件虚拟化技术(比如KVM、Xen或Hyper-V)擅长于在一个物理主机上运行多个 *** 作系统的完全隔离的实例,但这种虚拟化技术在性能、资源和资源配置时间等方面存在各种各样的开销。标准的机器虚拟化实际上可能没有必要,这取决于你的实际使用场合。

另外一种轻型虚拟化方法就是所谓的Linux容器(LXC),它提供了 *** 作系统级别的虚拟化。由于不存在运行虚拟机带来的开销,LXC让用户可以在轻型容器沙盒里面运行标准Linux *** 作系统的多个实例。如果你搭建一个可复制的开发/测试环境,或者在安全沙盒里面部署应用程序,容器就派得上大用场。

Docker就是为了便于部署Linux容器而开发的这样一款开源工具。Docker正迅速成为容器技术方面的一项事实上的标准,已经被诸如Ubuntu和红帽之类的各大Linux发行版所采用。

我在本教程中将演示如何在Ubuntu 14.04上,借助Docker管理Linux容器。请注意:对Ubuntu的早期版本而言, *** 作步骤可能略有不同。

眼下,Ubuntu上可用的Docker程序包只支持64位系统。想在32位机器上运行它,你就要利用源代码构建32位版本的Docker(详见这里)。

安装Docker

借助apt-get命令,安装Docker是件轻而易举的事。

$ sudo apt-get install docker.io

为了允许非根用户也可以运行Docker,将你自己添加到docker群组。下面这个命令会允许当前用户运行Docker,无需根用户权限。

$ sudo usermod -a -G docker $USER

退出,然后重新登录,以激活群组成员的变化。

下一步,编辑Docker配置文件,以便更新Docker二进制代码的位置。

$ sudo vi /etc/default/docker.io

DOCKER="/usr/bin/docker.io"

重启Docker服务。

$ sudo service docker.io restart

管理Docker容器

如果你想启动Ubuntu *** 作系统的一个新的Docker容器,首先需要获取Ubuntu Docker映像文件。下面这个命令会通过网络下载Docker映像文件。

$ docker pull ubuntu

你可以以一种交互模式来开启Ubuntu Docker,如下所示。最后一个参数“/bin/bash”是一旦启动就将在容器里面执行的命令,这里是一个简单的bash外壳命令。

$ docker run -i -t ubuntu /bin/bash

上述命令会立即启动一个Ubuntu容器(这正是容器的魅力所在!),并为你提供容器里面的外壳提示符。这时候,你应该能够访问沙盒环境里面的标准的Ubuntu *** 作系统了。

想退出Docker容器,在容器里面的提示符处键入“exit”。

你可以启动不同形式的容器。比如,想启动Fedora容器,请执行下面这个命令:

$ docker.io run -i -t fedora /bin/bash

如果本地没有Fedora Docker映像文件,该命令就会首先自动下载映像文件,然后启动Docker。

如果你想启动采用某个发行版版本的容器,也可以这么做。比如说,想启动Ubuntu 13.04 Docker,请执行下面这个命令:

$ docker.io run -i -t ubuntu:13.04 /bin/bash

容器网络

Docker使用Linux网桥将容器彼此互联起来,并将它们连接到外部网络。安装了Docker后,你应该会看到默认情况下自动组建的docker0 Linux网桥。你创建的每个容器都将连接到docker0网桥接口。

自定义Linux网桥

如果你想,也可以使用自定义Linux网桥将诸容器互联起来。为此,你可以建立一个自定义网桥,并对它进行配置,如下所示。你可以为该网桥分配一个单独的子网,并且从子网为Docker分配IP地址。我会使用10.0.0.0/24作为Docker子网。

$ sudo apt-get install bridge-utils

$ sudo brctl addbr br0

$ sudo ifconfig br0 10.0.0.1 netmask 255.255.255.0

想让Docker使用自定义网桥,将“-b=br0”添加到/etc/default/docker.io中的DOCKER_OPTS变量,然后重启Docker服务。

$ sudo service docker.io restart

至此,任何新的容器都会连接到br0,其IP地址会自动从10.0.0.0/24来分配。

其他定制

还有另外几种方法可以定制Docker的默认网络设置,主要是通过改动/etc/default/docker.io中的DOCKER_OPTS变量来实现。

“-dns 8.8.8.8 -dns 8.8.4.4”:指定容器使用的DNS服务器。

“-icc=false”:让诸容器彼此隔离开来。

故障排查

1. 运行docker.io命令时,你会遇到下面这个错误。

dial unix /var/run/docker.sock: no such file or directory(没有此类文件或目录)

出现这个错误,可能是由于Docker守护程序没在运行。检查Docker守护程序的状态,确保先启动它。

$ sudo service docker.io status

$ sudo service docker.io start


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7333405.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-04
下一篇 2023-04-04

发表评论

登录后才能评论

评论列表(0条)

保存