资源和工厂设计模式薄弱 [英] Weak resources and factory design pattern

查看:87
本文介绍了资源和工厂设计模式薄弱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想想如何最好地处理以下设计(伪C ++代码):

  class Display {

public:

Bitmap GetBitmap(uint16 width,uint16 height);

private:

//活动位图列表
std :: set< Bitmap>位图;
}

...其中Display是Bitmap对象的工厂。显示还必须跟踪在 std :: set 容器内的所有分配的位图,并且可以选择在任何时候使它们无效/删除(例如在全屏切换中)。

所以本质上Bitmap是一个弱的资源句柄,谁拿着句柄必须检查它是否有效,使用它之前。



我现在的理论解决方案是使用C ++智能指针:




  • GetBitmap c $ c>将返回 weak_ptr ,因此可以使用 weakBitmap.lock()

  • 内部位图std :: set容器将保存 shared_ptr< Bitmap> ,以便能够放弃弱位图指针。



实施给定设计的最佳方式是什么?

解决方案

我想你可能想考虑一下: (例如返回 boost :: shared_ptr< Bitmap> ),并且只保留对内部集合中的对象的弱指针(例如 std :: list< boost :: weak_ptr< Bitmap>> )。每当用户要求一个位图,做一个锁定你的集合,并添加一个新的位图。如果你的集合是一个列表,你可以安全地存储迭代器只是添加元素,并从以后的集合中删除它,从而处理销毁位图。



由于 boost :: shared_ptr :: lock 是原子的,它也将在多线程时工作。但你仍然需要保护访问集合与锁。



以下是示例代码:

  #include< boost / shared_ptr.hpp> 
#include< boost / weak_ptr.hpp>
#include< boost / noncopyable.hpp>
#include< boost / thread.hpp>

类显示;

类Bitmap:boost :: noncopyable
{
friend class Display;
Bitmap(int,Display * d):display(d)
{}

显示*
public:

〜Bitmap(); //见下面的定义
};

typedef boost :: shared_ptr< Bitmap> BitmapPtr;

class Display
{
typedef std :: list< boost :: weak_ptr< Bitmap>> bitmaps_t;
typedef std :: map< Bitmap *,bitmaps_t :: iterator> bitmap_map_t;
bitmaps_t bitmaps_;
bitmap_map_t bitmap_map_;
boost :: mutex mutex_;

friend class Bitmap;
void remove(Bitmap * p)
{
boost :: lock_guard< boost :: mutex> g(mutex_);
bitmap_map_t :: iterator i = bitmap_map_.find(p);
if(i!= bitmap_map_.end())
{
bitmaps_.erase(i-> second);
bitmap_map_.erase(i);
}
}

public:
〜Display()
{
boost :: lock_guard< boost :: mutex> g(mutex_);
for(bitmaps_t :: iterator i = bitmaps_.begin(); i!= bitmaps_.end(); ++ i)
{
BitmapPtr ptr = i-& ;
if(ptr)
ptr-> display = NULL;
}
}

BitmapPtr GetBitmap(int i)
{
BitmapPtr r(new Bitmap(i,this));
boost :: lock_guard< boost :: mutex> g(mutex_);
bitmaps_.push_back(boost :: weak_ptr< Bitmap>(r));
bitmap_map_ [r.get()] = - bitmaps_.end();
return r;
}
};

Bitmap ::〜Bitmap()
{
if(display)
display-> Remove(this);
}

请注意, Bitmap之间有双向链接显示 - 它们都保持一个弱指针,意味着他们可以自由地沟通。例如,如果您希望Display能够销毁位图,它可以通过将display更新为NULL来简单地禁用它们,如 Display 析构函数所示。 每次要访问Bitmap(析构函数中的示例)时,必须锁定 weak_ptr< Bitmap> 如果这种通信不经常发生,不应该是很大的问题。



对于线程安全,您可能需要在每次要禁用它时将Bitmap锁定,即将显示成员复位为NULL,并在每次要访问显示从位图。由于这有性能影响,您可能需要在位图中替换 Display * weak_ptr< Display> 。这也消除了对显示的析构函数的需要。这里是更新的代码:

  class Bitmap:boost :: noncopyable 
{
friend class Display;
Bitmap(int,const boost :: shared_ptr< Display>& d):display(d)
{}

boost :: weak_ptr< Display>显示;

public:
〜Bitmap(); //见下面的定义
};

typedef boost :: shared_ptr< Bitmap> BitmapPtr;

类显示:public boost :: enable_shared_from_this< Display>
,boost :: noncopyable
{
// ...这里没有改变

public:
BitmapPtr GetBitmap(int i)
{
BitmapPtr r(new Bitmap(i,shared_from_this()));
boost :: lock_guard< boost :: mutex> g(mutex_);
bitmaps_.push_back(boost :: weak_ptr< Bitmap>(r));
bitmap_map_ [r.get()] = --bitmaps_.end();
return r;
}
};

Bitmap ::〜Bitmap()
{
boost :: shared_ptr< Display> d(显示);
if(d)
d-> Remove(this);
}

在这种情况下,在Bitmap中禁用显示指针是线程安全的, ,如下所示:

  Display :: DisableBitmap(bitmaps_t :: iterator i)
{
BitmapPtr ptr = i-> lock();
if(ptr)
ptr-> display.reset();
}


Thinking of a way how to best approach the following design (pseudo C++ code):

class Display {

  public:

   Bitmap GetBitmap(uint16 width, uint16 height);

  private:

   // A list of active bitmaps
   std::set<Bitmap> bitmaps;
}

... where Display is a factory (and sole owner) for Bitmap objects. Display also has to track all the allocated bitmaps within a std::set container and may choose to invalidate/delete them at any time (like in a fullscreen switch).

So essentially a Bitmap is a weak resource handle and whoever holds the handle will have to check if it is valid before using it.

My theoretical solution right now is to use C++ smart pointers:

  • GetBitmap() will return a weak_ptr<Bitmap> and thus can be checked for validity using weakBitmap.lock().
  • Internal bitmaps std::set container will hold shared_ptr<Bitmap> so as to be able to give away weak bitmap pointers.

What is the best way to implement given design? Is there a de facto design pattern for given functionality I am missing?

解决方案

I think you may want to consider turning it around : give away the ownership of objects you have created (e.g. returning boost::shared_ptr<Bitmap>) and only retain weak pointers to objects in your internal collection (e.g. std::list<boost::weak_ptr<Bitmap>>). Whenever user asks for a Bitmap, do a lock on your collection and add a new Bitmap there. If your collection is a list you can safely store iterator to just added element and remove it from the collection later, thus handling destruction of a Bitmap.

Since boost::shared_ptr::lock is atomic, it will also work when multithreading. But you still need to guard access to collection with a lock.

Here is sample code:

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>

class Display;

class Bitmap : boost::noncopyable
{
  friend class Display;
  Bitmap(int, Display* d) : display(d)
  {}

  Display* display;
public:

  ~Bitmap(); // see below for definition
};

typedef boost::shared_ptr<Bitmap> BitmapPtr;

class Display
{
  typedef std::list<boost::weak_ptr<Bitmap>> bitmaps_t;
  typedef std::map<Bitmap*, bitmaps_t::iterator> bitmap_map_t;
  bitmaps_t     bitmaps_;
  bitmap_map_t  bitmap_map_;
  boost::mutex  mutex_;

  friend class Bitmap;
  void Remove(Bitmap* p)
  {
    boost::lock_guard<boost::mutex> g(mutex_);
    bitmap_map_t::iterator i = bitmap_map_.find(p);
    if (i != bitmap_map_.end())
    {
      bitmaps_.erase(i->second);
      bitmap_map_.erase(i);
    }
  }

public:
  ~Display()
  {
    boost::lock_guard<boost::mutex> g(mutex_);
    for (bitmaps_t::iterator i = bitmaps_.begin(); i != bitmaps_.end(); ++i)
    {
      BitmapPtr ptr = i->lock();
      if (ptr)
        ptr->display = NULL;
    }
  }

  BitmapPtr GetBitmap(int i)
  {
    BitmapPtr r(new Bitmap(i, this));
    boost::lock_guard<boost::mutex> g(mutex_);
    bitmaps_.push_back(boost::weak_ptr<Bitmap>(r));
    bitmap_map_[r.get()] = --bitmaps_.end();
    return r;
  }
};

Bitmap::~Bitmap()
{
  if (display)
    display->Remove(this);
}

Please note there is two-way link between Bitmap and Display - they both keep a weak pointer to each other, meaning they can freely communicate. For example, if you want Display to be able to "destroy" Bitmaps, it can simply disable them by updating "display" to NULL, as demonstrated in Display destructor. Display has to lock a weak_ptr<Bitmap> every time it wants to access the Bitmap (example in destructor) but this shouldn't be much of a problem if this communication does not happen often.

For thread safety you may need to lock Bitmap everytime you want to "disable" it i.e. reset display member to NULL, and lock it everytime you want to access "display" from Bitmap. Since this has performance implications, you might want to replace Display* with weak_ptr<Display> in Bitmap. This also removes need for destructor in Display. Here is updated code:

class Bitmap : boost::noncopyable
{
  friend class Display;
  Bitmap(int, const boost::shared_ptr<Display>& d) : display(d)
  {}

  boost::weak_ptr<Display> display;

public:
  ~Bitmap(); // see below for definition
};

typedef boost::shared_ptr<Bitmap> BitmapPtr;

class Display : public boost::enable_shared_from_this<Display>
              , boost::noncopyable
{
  //... no change here

public:
  BitmapPtr GetBitmap(int i)
  {
    BitmapPtr r(new Bitmap(i, shared_from_this()));
    boost::lock_guard<boost::mutex> g(mutex_);
    bitmaps_.push_back(boost::weak_ptr<Bitmap>(r));
    bitmap_map_[r.get()] = --bitmaps_.end();
    return r;
  }
};

Bitmap::~Bitmap()
{
  boost::shared_ptr<Display> d(display);
  if (d)
    d->Remove(this);
}

In this case "disabling" display pointer in Bitmap is thread safe without explicit synchronisation, and looks like this:

Display::DisableBitmap(bitmaps_t::iterator i)
{
  BitmapPtr ptr = i->lock();
  if (ptr)
    ptr->display.reset();
}

这篇关于资源和工厂设计模式薄弱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆