架构师进阶:Linux进程间如何共享内存

架构师进阶:Linux进程间如何共享内存,第1张

共享内存 IPC 原理

共享内存进程间通信机制主要用于实现进程间大量的数据传输,下图所示为进程间使用共享内存实现大量数据传输的示意图:

640

共享内存是在内存中单独开辟的一段内存空间,这段内存空间有自己特有的数据结构,包括访问权限、大小和最近访问的时间等。该数据结构定义如下:

from /usr/include/linux/shm.h

struct shmid_ds {

struct ipc_perm shm_perm/* operation perms *** 作权限 */

int shm_segsz/* size of segment (bytes) 段长度大小 */

__kernel_time_t shm_atime/* last attach time 最近attach时间 */

__kernel_time_t shm_dtime/* last detach time 最近detach时间 */

__kernel_time_t shm_ctime/* last change time 最近change时间 */

__kernel_ipc_pid_t shm_cpid/* pid of creator 创建者pid */

__kernel_ipc_pid_t shm_lpid/* pid of last operator 最近 *** 作pid */

unsigned short shm_nattch/* no. of current attaches */

unsigned short shm_unused/* compatibility */

void *shm_unused2/* ditto - used by DIPC */

void *shm_unused3/* unused */|

}

两个进程在使用此共享内存空间之前,需要在进程地址空间与共享内存空间之间建立联系,即将共享内存空间挂载到进程中。

系统对共享内存做了以下限制:

#define SHMMAX 0x2000000 /* max shared seg size (bytes) 最大共享段大小 */

#define SHMMIN 1 /* min shared seg size (bytes) 最小共享段大小 */

#define SHMMNI 4096 /* max num of segs system wide */

#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))|

define SHMSEG SHMMNI /* max shared segs per process */

Linux 共享内存管理

1.创建共享内存

#include <sys/ipc.h>#include <sys/shm.h>

/*

* 第一个参数为 key 值,一般由 ftok() 函数产生

* 第二个参数为欲创建的共享内存段大小(单位为字节)

* 第三个参数用来标识共享内存段的创建标识

*/

int shmget(key_t key, size_t size, int shmflg)

2.共享内存控制

#include <sys/ipc.h>#include <sys/shm.h>

/*

* 第一个参数为要 *** 作的共享内存标识符

* 第二个参数为要执行的 *** 作

* 第三个参数为 shmid_ds 结构的临时共享内存变量信息

*/

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

3.映射共享内存对象

系统调用 shmat() 函数实现将一个共享内存段映射到调用进程的数据段中,并返回内存空间首地址,其函数声明如下:

#include <sys/types.h>

#include <sys/shm.h>

/*

* 第一个参数为要 *** 作的共享内存标识符

* 第二个参数用来指定共享内存的映射地址,非0则为此参数,为0的话由系统分配

* 第三个参数用来指定共享内存段的访问权限和映射条件

*/

void *shmat(int shmid, const void *shmaddr, int shmflg)

4.分离共享内存对象

在使用完毕共享内存空间后,需要使用 shmdt() 函数调用将其与当前进程分离。函数声明如下:

#include <sys/types.h>

#include <sys/shm.h>

/*

* 参数为分配的共享内存首地址

*/

int shmdt(const void *shmaddr)

共享内存在父子进程间遵循的约定

1.使用 fork() 函数创建一个子进程后,该进程继承父亲进程挂载的共享内存。

2.如果调用 exec() 执行一个新的程序,则所有挂载的共享内存将被自动卸载。

3.如果在某个进程中调用了 exit() 函数,所有挂载的共享内存将与当前进程脱离关系。

程序实例

申请一段共享内存,父进程在首地址处存入一整数,子进程读出。

#include

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include

#include

#define SHM_SIZE 1024

int main()

{

int shm_id, pid

int *ptr = NULL

/* 申请共享内存 */

shm_id = shmget((key_t)1004, SHM_SIZE, IPC_CREAT | 0600)

/* 映射共享内存到进程地址空间 */

ptr = (int*)shmat(shm_id, 0, 0)

printf("Attach addr is %p ", ptr)

*ptr = 1004

printf("The Value of Parent is : %d ", *ptr)

if((pid=fork()) == -1){

perror("fork Err")

exit(0)

}

else if(!pid){

printf("The Value of Child is : %d ", *ptr)

exit(0)

}else{

sleep(1)

/* 解除映射 */

shmdt(ptr)

/* 删除共享内存 */

shmctl(shm_id, IPC_RMID, 0)

}

return 0

}

输出结果:

640

我也是新来的,不过对UNIX/LINUX, ORACLE, J2EE都非常有兴趣,以后希望大家互相交流

特写这篇安装教学作为见面礼

在Linux下,不更改Kernel也可能可以安装,步骤跟SOLARIS相同

但在SOLARIS下就一定要改内核参数了,我下面的教学就是针对Solaris Sparc/Intel`

在/etc/system最后加入这些:

set shmsys:shminfo_shmmax=4294967295

set shmsys:shminfo_shmmin=1

set shmsys:shminfo_shmmni=100

set shmsys:shminfo_shmseg=10

set semsys:seminfo_semmns=2000

set semsys:seminfo_semmsl=1000

set semsys:seminfo_semmni=100

set semsys:seminfo_semopm=100

set semsys:seminfo_semvmx=32767

unset TWO_TASK

重新启动,添加GROUP

groupadd dba

groupadd oinstall

然后添加用户

useradd -c "Oracle DBA" -d /home/oracle -g oinstall -G dba -m -u 300

passwd oracle

mkdir /var/opt/oracle

cd /var/opt/oracle

mkdir u01

mkdir u02

mkdir u03

mkdir u04

(Oracle推荐使用这种4DISK的模式来提高性能和可靠性,你不需要4DISK,不过可以分布到四个文件夹或分区)

ln -s /var/opt/oracle/u01 /u01

ln -s /var/opt/oracle/u02 /u02

ln -s /var/opt/oracle/u03 /u03

ln -s /var/opt/oracle/u04 /u04

chown oracle:oinstall /u01

chown oracle:oinstall /u02

chown oracle:oinstall /u03

chown oracle:oinstall /u04

chmod 755 /u01

chmod 755 /u02

chmod 755 /u03

chmod 755 /u04

登陆到oracle

修改.profile

加入

ORACLE_BASE=/u01/app/oracle

ORACLE_HOME=$ORACLE_BASE/product/8.1.7

ORACLE_SID=orcl

DBA=$ORACLE_BASE/admin

PATH=$PATH:$ORACLE_HOME/bin:/usr/local/bin

export ORACLE_BASE ORACLE_HOME ORACLE_SID DBA PATH

退出后重新登陆就可以安装了,这里的SID我命名为ORCL,你可以任意更改,当然用户和组也一样,安装时会问你DBA的组,选DBA就可以了

剩下的安装就应该很顺利了,完全按照ORACLE说的就可以.

!!!!!在Oracle 8i for Solaris Intel中有一个严重的BUG,会导致不能完成安装

Oracle建立/var/opt/oracle/oratab

但dbstart却去/etc/oratab寻找,所以导致startdb启动失败

ln -s /var/opt/oracle/oratab /etc/oratab

就可以解决这个问题

下面介绍如何在开机时自动启动ORACLE

在/etc/init.d下建立dbora

#!/bin/sh

ORA_HOME=/u01/app/oracle/product/8.1.7

ORA_OWNER=oracle

if [ ! -f $ORA_HOME/bin/dbstart ]

then

echo "Oracle startup: cannot start"

exit

fi

case "$1" in

'start') # Start Oracle Database and Net8 listener

su - $ORA_OWNER -c "$ORA_HOME/bin/dbstart" &

su - $ORA_OWNER -c "$ORA_HOME/bin/lsnrctl start" &

su - $ORA_OWNER -c "ORA_HOME/Apache/Apache/bin/apachectl start" &

'stop') # Stop Oracle Database and Net8 listener

su - $ORA_OWNER -c "$ORA_HOME/bin/dbshut" &

su - $ORA_OWNER -c "$ORA_HOME/bin/lsnrctl stop" &

su - $ORA_OWNER -c "ORA_HOME/Apache/Apache/bin/apachectl stop" &

esac

然后作一个连接

ln -s /etc/init.d/dbora /etc/rc2.d/S99dbora

ln -s /etc/init.d/dbora /etc/rc0.d/K10dbora

打开/var/opt/oracle/oratab

把N改为Y

orcl:/u01/app/oracle/product/8.1.7:[color=#DC143C]Y[/color]

这里,我用ORACLE用户运行APACHE,在安全上有很大漏洞,你可以换成其他没有权限的用户,APACHE使用的端口是7777,你如果要换成80端口,那还要作很多改动,这里不介绍


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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存