想要实现的功能:动态库中定义结构体类型全局变量(一个结构体中嵌套多个结构体),该变量在库内可读写,但主程序(外部程序)只可读,不可写。
方便说明,简化成一个如下的结构体变量:
typedef struct
{
int a;
int b;
int c;
} Test_STU;
思路:
- 结构体改成类,public成员,通过get()方法获取——不喜欢,直接采用 . 结构体方式访问最好;
- 结构体改成类,public成员,添加const修饰——不喜欢,变量很多,初始化列表不方便,且类内以及其它类内无法修改变量,而且const并非完全保证变量不会被修改,比如const_cast;
- 对于让外部程序可读可写的全局变量,库内定义好一个对该变量的引用,如:
Test_STU&Test,外部程序可通过extern &Test声明后使用;那么类似,针对只读的变量,库内定义时候使用const &修饰,如const Test_STU & Test,外部程序也通过extern &Test声明后使用——测试不行,const属性只在本编译模块有效,外部程序依然可以通过Test.a改写;
思考:本质上是想获取一个对某一片内存区域只有访问权限的指针!
思路:
联想多进程通信中的共享内存,在同一进程中使用shm_open打开同一文件,通过mmap建立两块内存映射区,获得操作该内存区域的指针,在建立映射区时,一个权限设为可读可写,一个权限设为只读……好像可以,试试……
动态库部分代码:
test.h
#ifndef TEST_H
#define TEST_H
#include "test_global.h"
#include <iostream>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct{
int a;
int b;
int c;
} Test_STU;
class test
{
public:
test();
Test_STU *getSTUAddress(); //提供给外部程序获取只读内存映射区的地址
};
#endif // TEST_H
test.cpp
#include "test.h"
Test_STU *APP_RO = nullptr;
test::test()
{
//创建共享内存过程
int fd = shm_open("shmfile", O_CREAT|O_RDWR|O_TRUNC, 0666);
if (fd < 0)
printf("shm_open failed!\n");
ftruncate(fd, sizeof(Test_STU));
//该映射区,库程序可读可写
Test_STU *BGD_RW;
BGD_RW = (Test_STU *) mmap(NULL, sizeof(Test_STU), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (BGD_RW == MAP_FAILED) {
perror("mmap failed!\n");
}
close(fd);
//再次打开同一个文件,创建第二个内存映射区,该映射区只读
int fd2 = shm_open("shmfile", O_RDWR, 0666);
if (fd2 < 0)
printf("shm_open failed!\n");
APP_RO = (Test_STU *) mmap(NULL, sizeof(Test_STU), PROT_READ, MAP_PRIVATE, fd2, 0);
if (APP_RO == MAP_FAILED) {
perror("mmap failed!\n");
}
close(fd2);
//库程序先随便赋值
BGD_RW->a = 100;
BGD_RW->b = 200;
BGD_RW->c = 300;
// munmap(APP_RO, sizeof(Test_STU));
// munmap(BGD_RW, sizeof(Test_STU));
// shm_unlink("shmfile");
}
Test_STU *test::getSTUAddress()
{
return APP_RO;
}
OK,生成动态库文件libtest.so
注意:编译生成动态库时需要添加链接选项:-lrt!(如果是用qt,则在.pro文件中添加:LIBS +=-lrt)
外部测试程序:
#include <iostream>
#include "test.h"
using namespace std;
int main()
{
test test1;
Test_STU *APP_RO; //我自己都没注意,变量名和库中定义的全局变量重名了…
APP_RO = test1.getSTUAddress();
cout<<APP_RO->a <<" "<<APP_RO->b<<" "<<APP_RO->c<<" "; //输出100 200 300
cout<<endl;
// APP_RO->a = 999; //报错,segment fault!,只读不可写
getchar();
return 0;
}
目的达到,至于效率,除了浪费些内存,也没啥大问题……嗯,还不在小白的研究层次……
另外两点:
- 如上代码,外部程序指针变量与库内定义的全局指针变量重名,对于只读没影响,特意用
BGD_RW测试了可读可写的情况,发现也没影响……好像解释的通,不管重不重名,不管是库内还是库外指针,操作的都是同一块内存区域; - mmap存在一个也许可以忽略也许不能忽略的问题:并不是每次写入内存,都会被立马同步到文件。对于上例,理论上来说,库程序修改了
Test中的值,shmfile文件可能不会立即改变,此时,如果外部程序读取的话,值可能还没变化。这个时间究竟多久,没去研究,保险起见似乎要用msync()函数强制同步。
最后,本文纯属好奇测试,权当学习记录~

1万+

被折叠的 条评论
为什么被折叠?



