查看文章 |
[S60] ARM平台独有问题 Writable Static Data in DLLs
2007-07-08 16:59
在编译arm平台程序的时候,出现如下错误提示: ERROR: Dll 'AppName[UID].APP' has initialised data. 或者: ERROR: Dll 'AppName[UID].APP' has uninitialised data. (扩展名APP的应用程序其实也是一个DLL。) 而在为模拟器编译的时候,这个问题不会出现。这曾经导致我在完成完整的设计,编码和调试后, 被迫放弃原有设计。 从这条错误信息的字面意思是什么也看不出来的。initialised 和 uninitialised都一样有问题。 其实真正的含义是Dll里存在可写的全局变量。 大家知道在程序运行的时候,DLL只会被装载一次。在Windows平台,每个进程都有自己独立的DLL空间。也就是说,不同进程装载同一个DLL,互相之间是独立的。只有在一个进程内,才是共享的。但是S60平台的设计是所有进程都共享同一个DLL空间。这样的设计显然是出于节约内存的目的,是很有必要的。但是这样就带来一个问题,那就是DLL里不可以有可写的全局变量,否则就要造成混乱。A进程对变量的改写会直接影响到B进程,这是程序设计者所不愿意看到的。所以,S60平台的编译器就禁止了在DLL内申明可写全局变量。但是全局变量还是可以用的,只要加上const申明即可。 一般来说,在做DLL设计的时候,的确不鼓励使用可写全局变量。即使是windows平台,DLL的可写全局变量也会在不同模块之间带来问题。当遇到这个编译器错误的时候,应该设法修改设计,回避使用全局变量。 但是因为APP实际上也是DLL,这就导致连S60的主程序也不能使用可写的全局变量,这个在某些时候就成了问题,全局变量毕竟是一个重要的实现手段。对此,S60提供了线程局部存储(thread local storage)来解决问题。 TLS的关键是两个函数: void Dll::SetTls(void*)和void* Dll::Tls() SetTls用于将任意类型的指针保存到线程局部存储中,而Tls()则取出该指针。 指针指向在堆上分配的一块内存。一个线程只能有一个局部存储变量。所以,如果你有很多全局变量,就要定义一个结构,把所有的全局变量封装在其中。这是挺别扭的,不过S60 3rd据说就支持dll的可写全局变量了。 tls样例代码: 设置 GlobalData* p = new GlobalData(); if ( p ) { Dll::SetTls( p ); } 使用 GlobalData* p = (GlobalData*) Dll::Tls(); |
最近读者: