我正在尝试构建对象,需要一段时间来构建一个单独的线程。 (稍后在实时加载游戏资产时,渲染循环正在运行:))
当对象仍在构建时,对该对象的请求不会失败,而是替换它。 (就像没有纹理的绘图一样,而纹理仍在加载,在游戏中)。 我的方法是使用State-Pattern - 一个状态可用于静止加载。 (我的第一个是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(...)
}
问题是(如代码中所述):
Construct()
界面中移动IState
方法以改进设计(如果对象已经可用,则放弃Construct()
调用!)Object
而不是Object*
吗?_CrtSetBreakAlloc
跟踪我自己的代码块?!)寻找您对设计的答案和评论。 (我刚刚开始处理软件架构,所以如果这种方法是垃圾,请纠正我;))
答案 0 :(得分:1)
这不是线程安全的,因为如果你调用Object::Use
并且在它正在使用时,另一个线程中的构造完成,它会删除仍然在主线程中使用的虚拟对象,从而导致未定义的行为
我现在看到两种方法:
shared_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()
完成执行后,在主线程中完成销毁。
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);
}
};