2021年1月18日 星期一

Global 物件在 cxxlObjectPlugin 插件須注意的問題

Global 物件指的是如下的用法:

class Global_t
{
  UTF8_String Hello{"Hello..."};

public:

  // Destructor
  ~Global_t()
  {
    cout << "Global_t::~Global_t()" << endl;
  }


  UTF8_String cxxlFASTCALL GetHello() const
  {
    return Hello;
  }
}g_Global;
 

特性有三:

  1. 程式或插件載入就會自動建好
  2. 任何可用到的使用端都能直接使用
  3. 程式或插件結束前會自動執行解構程序
問題就在其中有包含 UTF8_String,程式或插件結束時依機制並不直接執行其解構程序,而是交給 CxxlMan2 程式庫的垃圾處理機制。主程式還好,主程式結束後垃圾處理就不再運作。但若是插件,UTF8_String 要叫用解構程式時,插件已卸載了無法執行了。

解決的辦法有兩個方向,第一個不要在 Global 中有任何 cxxlObject 的成份;若非有不可就用以下建議的第二種方法,也許還有第三、第四...種方法也說不定
class Global_t;
Smart_Ptr<Global_t> cxxlFASTCALL Get_Global();

class Global_t:virtual public LifeObject<true>
{
  UTF8_String Hello{"Hello..."};

  // Constructor
  Global_t()
  {
    cout << "Global_t Constructor" << endl;
  }


public:

  // Destructor
  ~Global_t()
  {
    cout << "Global_t Destructor" << endl;
  }


  UTF8_String cxxlFASTCALL GetHello() const
  {
    return Hello;
  }

  friend Smart_Ptr<Global_t> cxxlFASTCALL Get_Global();
};

// 取得 Global_t 物件,若 Global_t 物件還不存在會先產生
Smart_Ptr<Global_t> cxxlFASTCALL Get_Global()
{
  static mutex mtx;


  class Notify_LifeMonitor;  

  // Globar_t 物件定義在這,須由 Get_Global() 取得
  static Smart_Ptr<Notify_LifeMonitor> m_Global_Ptr;

  // 作為 LifeMonitor 的通知處理,務必讓 LifeMonitor 被放棄持有
  // 這是為了讓 m_Notify_Global_Ptr 放棄持有 LifeMonitor 而量身訂作
  class Notify_LifeMonitor :public LifeMonitor<Global_t>
  {
  public:
    // Constructor
    Notify_LifeMonitor(const Smart_Ptr<Global_t>& Obj)
      :LifeMonitor<Global_t>(Obj)
    {
    }

    // 通知須把 LifeMonitor 釋放
    virtual void cxxlFASTCALL DoDelNotify() override
    {
      lock_guard<mutex> lck(mtx);
      m_Global_Ptr.Destroy();
    }
  };

  lock_guard<mutex> lck(mtx);
  if (m_Global_Ptr.isNULL())
  {
    // 在執行時期要用時才產生 Global_t 物件
    m_Global_Ptr = new Notify_LifeMonitor(new Global_t);
  }

  return m_Global_Ptr->GetLifeObject();
}

Global_t 不再做成 Global 物件,為了達到 Global_t 物件在插件結束前會自動執行解構程序,所以定義成 LifeObject<true>,才能在 dll 無使用時,Global_t 和 dll 可一起釋放,但 Global_t 會先釋放

範例下載:








沒有留言:

張貼留言