DLL中的可写静态数据
Symbian OS是基于ROM来处理程序的。DLL是通常是存储在ROM中的(运行也是在ROM中),所以它是不可写的。虽然有时把DLL装入RAM中运行,但Symbian OS仍旧假定DLL不可写。因此Symbian OS中的DLL没有数据段(Data Segment ),这就导致了DLL中不能包含有可写的静态数据,不管其是否被初始化。
静态数据是在函数之外定义的任何数据,例如:TbufC<20> filename;Void SetFileName()
{………………
}许多现在的程序广泛的使用了静态数据。在基于Windows的PC上运行模拟器并不会产生任何问题,因为DLL使用的是Windows下的DLL机制,而Windows下的DLL是允许有可写数据的。任何这样的代码不能被其它平台编译,编译失败并从pertran返回一个警告(pertran是为其它平台编译的最后一阶段使用的工具)。Pertran产生类似下的警告的信息:ERROR: Dll 'MENUITEMS[10008AD0].APP' has uninitialised data.为了消除这个错误必须从DLL中除去所有的可写静态数据。
DLL中含有数据(可写的)在一些情况中是很有用的,所以Symbian OS提供了一种机制允许DLL基于每个线程(per-thread basis)管理很少数量的私有存储区------线程本地存储(Thread Local Storage, 可以参考SDK文档Threads and Processes Overview和例子(Symbian\7.0s\Series60_v20\Examples\base\threadsandprocesses下的tls1和tls2)。这种机制使得每个DLL的使用者看不到同一个DLL的其它使用者的私有存储区(Thread-Local Storage)。
移植策略去掉可写的静态数据是一个很重的任务。一般情况下,你需要把所有的静态数据放到一个struct里,然后在那些需要用到的地方通过指针访问这个结构。
下面是使指针可用的几种方法,包括:1.在每个用到的函数中把指针添加为参数。这种方法需要考虑的是代码的改变——不仅仅是那些直接使用静态数据的函数,还包括间接调用该函数的函数。
2.使用上面提到的DLL线程本地存储(Thread-Local Storage)。这种方法可能会引起一些性能上的问题,因为使用它的DLL函数要比直接解引用指针复杂的多。
3.把指针存储在那些需要用到它的struct和class中。这也会引起一些代码的改变,但是消除了需要改变间接调用函数的缺点和频繁访问线程本地存储(Thread-Local Storage)的缺点。
在实践中,经常需要结合上面的3种方法来使用,以达到代码和性能的最小改变。
设计策略新的代码在设计时应该避免使用可写静态数据。在面向对象系统中,不用考虑全局数据与对象一起通过指针传递的情况,因为可以通过this指针调用非静态成员函数来访问对象的所有成员。
通过适当的面向对象设计可以很自然的避免可能用到可写静态数据的情况。
隐式使用可写静态数据有时可通过隐式的方法来使用可写静态数据,例如:const TRgb(255,255,255) KRgbWhite;定义一个不会被Symbian代码改变的常量。然而,TRgb是一个类,为了构造这个常量,必须在运行时调用其构造函数,因此对设备来说这个常量是可写的。
要避免这种情况可以通过下面的代码定义常量:#define KRgbWhite TRgb(255,255,255)
这样类的构造函数就被移到使用点上才被调用而不是DLL被加载时。
EXE中的可写静态数据在EXE中不限制使用可写静态数据。做为server的EXE可能需要可写静态数据。
线程本地存储(Thread-Local Storage)
Symbian OS中的线程本地存储(Thread-Local Storage)允许每个DLL的每个线程可以有一个机器字的静态数据。这个字只能被每个DLL线程的DLL代码访问。也就是说同一个DLL的不同线程拥有不同的一个机器字空间而且它们之间是不可见的。
Dll类提供了使用线程本地存储(Thread-Local Storage)的接口。只需要调用它的静态成员函数SetTls(),Tls()就可以存储/访问线程本地存储(Thread-Local Storage)的数据了。具体可以参考SDK文档和例子(Symbian\7.0s\Series60_v20\Examples\base\threadsandprocesses下的tls1和tls2)