0

我正在尝试构建对象,这需要一段时间才能在单独的线程中构建。(稍后在渲染循环运行时实时加载游戏资源:))

当对象仍在构建时,对该对象的请求不会失败,而是做一些替换。(就像在游戏中绘制没有纹理,而纹理仍在加载时)。我的方法是使用状态模式 - 一种状态表示可用的状态,用于仍在加载。(我的第一个是 Proxy,但你真的不想看到那个代码!)

这是完整的源代码:

#include <thread>
#include <iostream>
#include <list>
using namespace std;


class Object
{
private:
    int _data;
    /// Classes for states ///
    class IState
    {
    public:
        virtual void Use(Object *obj) = 0;
    };
    class Unavailable : public IState
    {
    public:
        void Use(Object *obj)
        {cout << "Object not avaiable..." << endl;}
    };
    class Avaiable : public IState
    {
    public:
        void Use(Object *obj)
        {cout << "Data is: " << obj->_data << endl;}
    };
    ////////////////////////
    IState *_state;
    void ChangeState(IState *newstate)
    {
        delete _state;
        _state = newstate;
    }
    void Construct() //Can this be part of IState?
    {
        this_thread::sleep_for(chrono::seconds(1)); //Work hard
        _data = 50;
        ChangeState(new Avaiable());
    }
public:
    Object()
    {
        //Set the state to unavaiable
        _state = new Unavailable();
        //Construct the object in seperate thread
        thread constructor(&Object::Construct, this); //How do I refer to Construct if its a member of IState?
        constructor.detach();
        //Thread runs while out of scope!
    } 
    ~Object()
    {delete _state;}

    void Use()
    {
        //Redirect actions
        _state->Use(this);
    }
};


int main()
{
    {
        list<Object*> objects;
        for (int i = 0; i < 10; i++)
        {
            this_thread::sleep_for(chrono::milliseconds(500));
            objects.push_back(new Object()); //I can't use Object as the list type, because of push_back()
                                             //copying the Object then DELETING it, thus deleting the state
            for (auto obj : objects) //The objects, which are already build shoud write "50"
                                     //otherwise it should write "Not avaiable" as a replacement
            {
                obj->Use();
            }
        }
        //Free the objects (I really want to avoid this....)
        for (auto obj : objects)
            delete obj;
    } //Extra scope to prevent false memory leaks!
    _CrtDumpMemoryLeaks(); //Reports memory leak somewhere. Couldn't track the block back to my code(...)
}

问题是(如代码中所述):

  1. 我如何Construct()在 -interface 中移动方法IState以改进设计(Construct()如果对象已经可用,则丢弃调用!)
  2. 我可以列出一个Object代替的列表Object*吗?
  3. 那内存泄漏可能是什么?(我无法用 ?! 将块追踪回我自己的代码_CrtSetBreakAlloc?!)

期待您对设计的回答和评论。(我刚开始处理软件架构,所以如果这种方法是垃圾,请纠正我;))

4

1 回答 1

1

那不是线程安全的,因为如果您调用Object::Use并且在使用它时,另一个线程中的构造完成,它会删除仍在主线程中使用的虚拟对象,从而导致未定义的行为。

我现在看到两种方法:

1而不是一个普通的指针,使用 ashared_ptr

class Object
{
private:
    int _data;
    std::shared_ptr<IState> _state;
    void ChangeState(std::shared_ptr<IState> newstate) {
      std::atomic_exchange(&_state, std::move(newstate));
    }
    void Construct() {
      //...
      ChangeState(std::make_shared<Avaiable>());
    }
public:
    Object() : 
      _state{std::make_shared<Unavailable>()}
    {
      std::thread constructor(&Object::Construct, this); 
      constructor.detach();
    } 
    ~Object()
    {}

    void Use() {
      std::shared_ptr<IState> currentState = std::atomic_load(&_state); //!!
      currentState->Use(*this)
    }
};

atomic_load状态很重要,它复制当前状态,shared_ptr整个Use操作在旧状态上执行,即使它同时被交换。然后在Use()完成执行后在主线程中完成销毁。

2 使用future并积极寻找构造的对象:

class Object
{
private:
    int _data;
    typedef std::unique_ptr<IState> StatePtr;
    typedef std::future<StatePtr()> Constructor; 

    StatePtr _state;
    Constructor _constructor

    StatePtr  Construct() {
      //...
      return std::make_unique<Avaiable>();
    }

    static bool isReady(Constructor& ctor) {
      return ctor.valid()
        && ctor.wait_for(std::chrono::seconds(0)) != std::future_status::timeout;
    }

    IState& getState() {
      if (isReady(_constructor)) {
        _state = _constructor.get();
        _constructor.reset();
      }
      return *_state;
    }

   
public:
    Object() : 
      _state{std::make_unique<Unavailable>()} ,
      _constructor{ std::async(std::launch::async, [this](){Construct();} )}
    {} 

    void Use() {
      getState().Use(*this);
    }
};
于 2013-09-07T12:18:23.573 回答