我在下面为异步资源管理器编写了Resource类。在加载期间,将使用默认资源(例如黑色纹理)创建一个Resource对象,以便将使用Resource的主线程不必等待,即使它是空白资源也是如此。加载完成后,加载器线程将调用setResource()并将基础资源设置为新加载的资源。但是也涉及所有权。因此,当加载完成时,新分配的资源将归Resource类所有,以便可以在销毁Resource或调用另一个setResource时将其释放,因为磁盘上的文件已更改并且需要重新加载。
template <typename T>
class Resource {
protected:
// Underlying object
std::atomic<T*> resource;
// Do I own resource
bool isOwner;
// Id of resource for faster mapping
uint64_t id;
// Name
std::string name;
public:
Resource(T* res) : resource(res), isOwner(false), id(0), name("non") {}
Resource(std::unique_ptr<T>&& res)
: resource(res.release()), isOwner(true), id(0), name("non") {}
~Resource() {
if (isOwner) delete resource.load(std::memory_order_acquire);
}
Resource(Resource&&) = default;
Resource(const Resource&) = delete;
Resource& operator=(const Resource&) = delete;
T* getResource() {
return resource.load(std::memory_order_acquire);
}
void setResource(T* res, bool own = false) {
if (isOwner) {
delete resource.load(std::memory_order_acquire);
}
isOwner = own;
resource.store(res, std::memory_order_release);
}
void setResource(std::unique_ptr<T>&& res) {
if (isOwner) {
delete resource.load(std::memory_order_acquire);
}
isOwner = true;
resource.store(res.release(), std::memory_order_release);
}
void setId(uint64_t idd) { id = idd; }
};
在这种情况下,是否存在isOwner上的数据争用,还是atomic.store()充当围栏?还是应该更改整个所有权方法,而只使用我不知道是否可行的std::atomic<std::shared_ptr<T>>
?
答案 0 :(得分:1)
当代码执行delete resource.load(std::memory_order_acquire);
时,另一个线程可能仍在使用该资源,因此这是竞争条件。
一个简单的解决方法是永远不要删除现有资源。您可以将黑色纹理用作具有静态存储持续时间的全局对象,该静态存储持续时间在整个应用程序执行期间都有效。
另一种方法是让getResource
返回std::shared_ptr<T>
(按值),以便旧资源在其最后一个用户处置时自动销毁。例如:
struct NullDeleter {
template<class T>
void operator()(T const&) {}
};
template<typename T>
class Resource {
protected:
std::shared_ptr<T> resource;
public:
Resource(T& res) : resource(&res, NullDeleter{}) {}
Resource(std::shared_ptr<T> const& res) : resource(res) {}
std::shared_ptr<T> getResource() {
return atomic_load(&resource);
}
void setResource(std::shared_ptr<T> const& res) {
atomic_store(&resource, res);
}
};