分享
 
 
 

如何在RedHatLinux中使用共享对象

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

充分利用共享内存并不总是容易的。在本文中,IBM 的 Sachin Agrawal 与我们共享了他的 C++ 专门技术,展示了面向对象如何去利用一个独特而实用的进程间通信通道的关键优势。

就时间和空间而言,共享内存可能是所有现代操作系统都具备的最高效的进程间通信通道。共享内存 同时将地址空间映射到多个进程:一个进程只需依附到共享内存并像使用普通内存一样使用它,就可以开始与其他进程进行通信。

不过,在面向对象编程领域中,进程更倾向于使用共享对象而不是原始的信息。通过对象,不需要再对对象中容纳的信息进行序列化、传输和反序列化。共享对象也驻留在共享内存中,尽管这种对象“属于”创建它们的进程,但是系统中的所有进程都可以访问它们。因此,共享对象中的所有信息都应该是严格与特定进程无关的。

这与当前所有流行的编译器所采用的 C++ 模型是直接矛盾的:C++ 对象中总是包含指向各种 Vee-Table 和子对象的指针,这些是 与特定进程相关的。要让这种对象可以共享,您需要确保在所有进程中这些指针的目标都驻留在相同的地址。

在一个小的示例的帮助下,本文展示了在哪些情况下 C++ 模型可以成功使用共享内存模型,哪些情况下不能,以及可能从哪里着手。讨论和示例程序都只限于非静态数据成员和虚函数。其他情形不像它们这样与 C++ 对象模型关系密切:静态的和非静态非虚拟的成员函数在共享环境中没有任何问题。每个进程的静态成员不驻留在共享内存中(因此没有问题),而共享的静态成员的问题与这里讨论到的问题类似。

环境假定

本文仅局限于用于 32 位 x86 Interl 体系结构的 Red Hat Linux 7.1,使用版本 2.95 的 GNU C++ 编译器及相关工具来编译和测试程序。不过,您同样可以将所有的思想应用到任意的机器体系结构、操作系统和编译器组合。

示例程序

示例程序由两个客户机构成:shm_client1 和 shm_client2,使用由共享对象库 shm_server 提供的共享对象服务。对象定义在 common.h 中:

清单 1. common.h 中的定义

#ifndef __COMMON_H__

#define __COMMON_H__

class A {

public:

int m_nA;

virtual void WhoAmI();

static void * m_sArena;

void * operator new (unsigned int);

};

class B : public A {

public:

int m_nB;

virtual void WhoAmI();

};

class C : virtual public A {

public:

int m_nC;

virtual void WhoAmI();

};

void GetObjects(A ** pA, B ** pB, C ** pC);

#endif //__COMMON_H__

清单 1 定义了三个类(A、B 和 C),它们有一个共同的虚函数 WhoAmI()。基类 A 有一个名为 m_nA 的成员。定义静态成员 m_sArena 和重载操作 new() 是为了可以在共享内存中构造对象。类 B 简单地从 A 继承,类 C 从 A 虚拟地继承。为了确保 A、B 和 C 的大小明显不同,定义了 B::m_nB 和 C::m_nC。这样就简化了 A::operator new() 的实现。GetObjects() 接口返回共享对象的指针。

共享库的实现在 shm_server.cpp 中:

清单 2. 库 - shm_server.cpp

#include <sys/types.h

#include <sys/ipc.h

#include <sys/shm.h

#include <errno.h

#include <stdio.h

#include <iostream

#include "common.h"

void * A::m_sArena = NULL;

void * A::operator new (unsigned int size)

{

switch (size)

{

case sizeof(A):

return m_sArena;

case sizeof(B):

return (void *)((int)m_sArena + 1024);

case sizeof(C):

return (void *)((int)m_sArena + 2048);

default:

cerr << __FILE__ << ":" << __LINE__ << " Critical error" <<

endl;

}

}

void A::WhoAmI() {

cout << "Object type: A" << endl;

}

void B::WhoAmI() {

cout << "Object type: B" << endl;

}

void C::WhoAmI() {

cout << "Object type: C" << endl;

}

void GetObjects(A ** pA, B ** pB, C ** pC) {

*pA = (A *)A::m_sArena;

*pB = (B *)((int)A::m_sArena + 1024);

*pC = (C *)((int)A::m_sArena + 2048);

}

class Initializer {

public:

int m_shmid;

Initializer();

static Initializer m_sInitializer;

};

Initializer Initializer::m_sInitializer;

Initializer::Initializer()

{

key_t key = 1234;

bool bCreated = false;

m_shmid = shmget(key, 3*1024, 0666);

if (-1 == m_shmid) {

if (ENOENT != errno) {

cerr << __FILE__ << ":" << __LINE__ << " Critical error" <<

endl;

return;

}

m_shmid = shmget(key, 3*1024, IPC_CREAT | 0666);

if (-1 == m_shmid) {

cerr << __FILE__ << ":" << __LINE__ << " Critical error" <<

endl;

return;

}

cout << "Created the shared memory" << endl;

bCreated = true;

}

A::m_sArena = shmat(m_shmid, NULL, 0);

if (-1 == (int)A::m_sArena) {

cerr << __FILE__ << ":" << __LINE__ << " Critical error" <<

endl;

return;

}

if (bCreated) {

// Construct objects on the shared memory

A * pA;

pA = new A;

pA-m_nA = 1;

pA = new B;

pA-m_nA = 2;

pA = new C;

pA-m_nA = 3;

}

return;

}

让我们更详细地研究清单 2:

第 9-25 行:operator new ()

同一个重载的操作符让您可以在共享内存中构造类 A、B 和 C 的对象。对象 A 直接从共享内存的起始处开始。对象 B 从偏移量 1024 处开始,C 从偏移量 2048 处开始。

第 26-34 行:虚函数

虚函数简单地向标准输出写一行文本。

第 35-39 行:GetObjects

GetObjects() 返回指向共享对象的指针。

第 40-46 行:初始化器(Initializer)

这个类存储共享内存标识符。它的构造函数创建共享内存及其中的对象。如果共享内存已经存在,它就只是依附到现有的共享内存。静态成员 m_sInitializer 确保在使用共享库的客户机模块的 main() 函数之前调用构造函数。

第 48-82 行:Initializer::Initializer()

如果原来没有共享内存,则创建,并在其中创建共享对象。如果共享内存已经存在,对象的构造就会被跳过。Initializer::m_shmid 记录标识符,A::m_sArena 记录共享内存地址。

即使所有进程都不再使用它了,共享内存也不会被销毁。这样就让您可以显式地使用 ipcs 命令来销毁它,或者使用 ipcs 命令进行一些速查。

客户机进程的实现在 shm_client.cpp 中:

清单 3. 客户机 - shm_client.cpp

#include "common.h"

#include <iostream

#include <stdlib.h

int main (int argc, char * argv[])

{

int jumpTo = 0;

if (1 < argc) {

jumpTo = strtol(argv[1], NULL, 10);

}

if ((1 jumpTo) || (6 < jumpTo)) {

jumpTo = 1;

}

A * pA;

B * pB;

C * pC;

GetObjects(&pA, &pB, &pC);

cout << (int)pA << "\t";

cout << (int)pB << "\t";

cout << (int)pC << "\n";

switch (jumpTo) {

case 1:

cout << pA-m_nA << endl;

ca

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有