随笔 - 2, 文章 - 73, 评论 - 60, 引用 - 0
数据加载中……

[S60]ARM平台独有问题 Writable Static Data in DLLs

[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();

 

在Symbian上如何定义全局变量

方法1(推荐)把这个变量定义成AppUi类的私有成员,在创建view时将这个变量传引用(或传指针)到view中,这样view就能随时访问它了。

方法2.把这个变量定义成AppUi类的私有成员,并为它写公共的访问函数
// CMyAppUi
public: // new methods
   TInt Share(); // return iShare
private:
JAVA手机网[www.cnjm.net]   TInt iShare;
在View里通过下面的方式访问这个变量:
// 如果View继承自CAknView
CMyAppUi* appUi = static_cast<CMyAppUi*>(AppUi());
appUi->Share(); // :)
// 如果View是其它类型
CMyAppUi* appUi = static_cast<CMyAppUi*>(CCoeEnv::Static()->AppUi());
appUi->Share(); // :)
方法3.使用单态类,参考诺基亚论坛上的文档:
Tip Of The Month: How To Implement A Singleton Class In Symbian OS



 

How to implement a singleton class in Symbian OS        ID: TTS000222

Version 1.1
Published at www.forum.nokia.com on October 19, 2006.

Overview

The singleton pattern is one of the best-known patterns in software engineering. Essentially, a singleton is a class which only allows a single instance of itself to be created, and usually gives simple access to that instance.

How to use thread local storage (TLS) to implement a singleton class

In Symbian OS, each DLL that is loaded in each thread has a machine word of thread-specific memory that can be written to and read — but no other static memory, which is why you can't have static class member variables. Since static class member variables are usually used to implement the singleton pattern, in Symbian OS we have to get around this, for instance by using TLS.

The following code demonstrates a singleton object whose NewL function uses TLS to test whether an object of its own type has been created. If it has, it simply returns the pointer stored in TLS, converted to its own type. If not, it instantiates an object of its own type, stores it in TLS, and then returns it.

Note that this assumes that no other class in the DLL that includes this class uses TLS. If this is not the case, you must write a singleton manager class, which uses TLS to store a pointer to a structure of pointers to all the singleton classes that the program needs.

Example 1: Singleton implementation based on TLS

  ==============

  CMySingleton.h

  ==============

 

  class CMySingleton : public CBase

      {

  public: // constructor and destructor

      static CMySingleton* NewL();

      virtual ~CMySingleton();

  private: // constructors

      CMySingleton(); // private because of the singleton pattern; it is

                      // guaranteed that only NewL will call it

      void ConstructL();

  public: // other functions

      ...

  private: // other functions

      ...

  private: // data

      ...

      }

 

  ================

  CMySingleton.cpp

  ================

 

  CMySingleton::CMySingleton* NewL()

      {

      CMySingleton* singleton;

      // Check thread local storage:

      if ( Dll::Tls() == NULL )

          {

          // TLS is still null, which means that no CMySingleton has

          // been instantiated yet.  Do so now, and return that

          // instance:

          singleton = new ( ELeave ) CMySingleton();

          CleanupStack::PushL( singleton );

          singleton->ConstructL();

          CleanupStack::Pop( singleton );

          // Store a pointer to the new instance in thread local storage:

          TInt err = Dll::SetTls( static_cast<TAny*>( singleton ) );

          if ( err == KErrNone )

              {

              return singleton;

              }

          else

              {

              delete instance;

              User::Leave( err );

              return NULL;

              }

          }

      else

          {

          // CMySingleton has been instantiated once already, so return

          // that instance:

          singleton = static_cast<CMySingleton*>( Dll::Tls() );

          return singleton;

          }

      }

 

TLS on S60 3rd Edition

Since applications from S60 3rd Edition onwards are implemented as EXE programs, Dll::Tls() is not available anymore. Instead, TLS functionality is implemented in UserSvr class (e32svr.h):

static TInt DllSetTls(TInt aHandle, TAny *aPtr);

static TAny *DllTls(TInt aHandle);

static void DllFreeTls(TInt aHandle);

Note that EXE programs can contain writeable static data, but this is not recommended to be used except as a last resort.

Using class CCoeStatic to implement a singleton class

A simpler way of implementing singletons than using TLS is possible for those classes which use the CCoeEnv class. Since CCoeEnv is a part of the UI control framework, this concerns only applications, not application engines.

This applies also to S60 3rd Edition and later editions.

Example 2: Singleton implementation based on CCoeStatic

  ==============

  CMySingleton.h

  ==============

 

  /**

   * Example implementation of a singleton class by means of inheriting

   * from CCoeStatic.

   */

  class CMySingleton : public CCoeStatic

      {

 

  public: // constructors and destructor   

 

      /**   

       * Returns an instance of this class. When called for the first

       * time, a new instance is created and returned.  After that,

       * calling InstanceL returns the same instance that was created

       * earlier.

       *  

       * @return A pointer to a CMySingleton object   

       */   

      static CMySingleton* InstanceL();   

 

  private: // constructor

 

      /**   

       * Default constructor is private because we are using the

       * singleton design pattern.

       */   

      CMySingleton();   

 

      ...

 

      }

 

 

  ================

  CMySingleton.cpp

  ================

 

  // -------------------------------------------------------------------------

  // CMySingleton::CMySingleton

  // C++ default constructor. It is private because we are using the

  // singleton design pattern.

  // -------------------------------------------------------------------------

  CMySingleton::CMySingleton()

      : CCoeStatic( KUidMySingleton )

      {

      }

 

  // -------------------------------------------------------------------------

  // CMySingleton::InstanceL

  // Returns an instance of this class. When called for the first time,

  // a new instance is created and returned.  After that, calling

  // InstanceL returns the same instance that was created earlier.

  // Note that the UID passed to CCoeEnv::Static needs to be unique.

  // -------------------------------------------------------------------------

  CMySingleton* CMySingleton::InstanceL()

      {

      CMySingleton* instance = static_cast<CMySingleton*>

          ( CCoeEnv::Static( KUidMySingleton ) );

      if ( !instance )

          {

          instance = new ( ELeave ) CMySingleton;

          CleanupStack::PushL( instance );

          instance->ConstructL();

          CleanupStack::Pop();

          }

      return instance;

     }

posted on 2008-06-02 20:23 郭天文 阅读(934) 评论(0)  编辑 收藏 引用 所属分类: S60


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理