资源预览内容
第1页 / 共22页
第2页 / 共22页
第3页 / 共22页
第4页 / 共22页
第5页 / 共22页
第6页 / 共22页
第7页 / 共22页
第8页 / 共22页
第9页 / 共22页
第10页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
Unix/Linux 下一般想让某个程序在后台运行,很多都是使用 作用:当动态链接库操作函数执行失败时,dlerror 可以返回出错信息,返回值为NULL 时表示操作函数执行成功。3.1.2 dlopen原型:1.void *dlopen (const char *filename, int flag); 作用:dlopen 用于打开指定名字(filename)的动态链接库,并返回操作句柄。参数说明:filename: so 文件名.如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。(1) 用户环境变量中的 LD_LIBRARY 值;(2) 动态链接缓冲文件/etc/ld.so.cache(3) 目录/lib,/usr/lib.flag:表示在什么时候解决未定义的符号(调用)。取值有两个:1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。2) RTLD_NOW : 表明在 dlopen 返回前就解决所有未定义的符号,一旦未解决,dlopen 将返回错误。dlopen 调用失败时,将返回 NULL 值,否则返回的是操作句柄。3.1.3 dlsym原型:1.void *dlsym(void *handle, char *symbol); 作用:dlsym 根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。举例:1.void handle =NULL; 2.void (*add)(int x,int y); 3. 4.handle =dlopen(“xxx.so“,RTLD_LAZY); 5.if (!handler) 6. printf( “加载模块错误 %sn“, dlerror() ); 7. return; 8. 9.add=dlsym(handle,“add“); 10.if(add) 11. add(89,369); 12.dlclose(handle); 3.1.4 dlclose原型:1.int dlclose (void *handle); 作用:dlclose 用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为 0时,才会真正被系统卸载。充分利用共享内存并不总是容易的。在本文中,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 #include #include #include #include #include #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 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 行:GetObjectsGetObjects() 返回指向共享对象的指针。第 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 #include int main (int argc, char * argv)int jumpTo = 0;if (1 jumpTo) | (6 m_nA WhoAmI();case 3:cout m_nA WhoAmI();case 5:cout m_nA WhoAmI();return 0;#include void DoNothingCode() pthread_create(NULL, NULL, NULL, NULL);第 6-35 行客户机进程获得指向三个共享对象的指针,建立对它们的数据成员的三个引用,并且 依赖于命令行的输入 调用三个虚函数。第 36-39 行没有被调用的 pthread_create() 函数用来强制链接到另一个共享库。来自所有共享库的任何方法都可以满足这一目的。共享库和客户机可执行文件的两个实例的编译方法如下:gcc shared g shm_server.cpp o libshm_server.so lstdc+gcc -g shm_client.cpp -o shm_client1 -lpthread -lshm_server -L .gcc -g shm_client.cpp -o shm_client2 -lshm_server -L . lpthread注意,交换了 shm_client1 和 shm_client2 中 shm_server 和 pthread 的链接顺序,以确保 shm_server 共享库在两个可执行文件中的基址不同。可以使用 ldd 命令进一步验证这一点。示例输出通常如下所示:清单 4. shm_client1 的库映射ldd shm_client1libpthread.so.0 = (0x4002d000)libshm_server.so = (0x40042000)libc.so.6 = (0x4005b000)ld-linux.so.2 = (0x40000000)清单 5. shm_client2 的库映射ldd shm_client2libshm_server.so = (0x40018000)libpthread.so.0 = (0x40046000)libc.so.6 = (0x4005b000)ld-linux.so.2 = (0x40000000)这里的主要目的是使构建的两个客户机二进制文件具有不同的服务器库基址。在这个示例程序的上下文中,使用不被调用的 pthread_create() 函数和不同的共享库链接顺序来达到这一目标。不过,没有具体规则或统一步骤可以作用于所有链接;需要根据不同的情况采取不同的方法。例 1:shm_client1 与 shm_client1在下面的输出中,首先在 shell 中调用 shm_client1。由于现在没有共享对象,于是 shm_client1 创建了它们,引用它们的数据成员,调用它们的虚函数,然后退出 将对象留在了内存中。第二次,进程只是引用数据成员和虚函数。清单 6. shm_client1 与 shm_client1 的输出日志$ ./shm_client1Created the shared memory1073844224 1073845248 10738462721Object type: A2Object type: B3Object type: C$ ipcs- Shared Memory Segments -key shmid owner perms bytes natt
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号