相当于 FIFO 释放顺序的 RAII
RAII equivalent for FIFO release order
RAII 非常舒适,我很难为资源提供等效设计,这些资源必须按照获取它们的顺序(FIFO)释放,而不是按照自然产生的相反顺序(堆栈)释放RAII.
在我的具体情况下,我有一个 stream
class 如下:
template<typename T>
class stream {
...
public:
// Producer API
T& write_acquire(); // This acquires a storage element and will "block"
// until a slot is available in the underlying resource
void write_release(&T); // This releases the storage element, transferring the data to a consumer
// Consumer API
T& read_acquire(); // This acquires a storage element and will "block"
// until a slot has been write_release
void read_release(&T); // This releases the storage element making it available
// for a potential future write_acquire
};
我正在考虑提供一个 RAII 风格的助手:
template<typename T>
class stream_wslot {
stream<T> &s;
T &slot;
public:
stream_wslot(stream<T> &s) : s{s}, slot{s.write_acquire()} {}
~stream_wslot() { s.write_release(slot); }
operator T&() { return slot; }
T& operator=(T &val) { return slot = val; }
};
但问题是以下用法将无法正常运行:
void test(stream<float> &fifo) {
stream_wslot even(fifo);
stream_wslot odd(fifo);
... first ...
... second ...
// releases odd !!!
// releases even
}
即先释放odd
槽,再释放even
槽。虽然我可以在 stream
中添加一个 "reordering" 队列,但我想知道是否有一种 "clean" 方法可以将 RAII 推广到这些情况。
使用 std::optional
,成本非常适中,最小的开销提供了对构建的更多控制,以及定义明确的销毁顺序。这正是您要找的,在这里。
例如:
std::optional<stream_wslot> o_even;
std::optional<stream_wslot> o_odd;
o_odd.emplace(fifo);
o_even.emplace(fifo);
auto &even=*o_even;
auto &odd=*o_odd;
从现在开始,使用 odd
和 even
的现有代码将很难区分。总计:odd
首先构建,even
第二构建。 odd
首先被销毁,当离开这个范围时, even
第二个被销毁。相同有效的构造和销毁顺序。
您可以在另一个线程上有一个队列 运行 以异步实现 FIFO 逻辑。如果 wslot
对象是使用对该队列的引用构造的,它们可以告诉它在它们析构时为它们执行 write_release()
,但在构造时执行常规 write_acquire()
,这将在必要时阻塞.
(或者,在构建时,他们可以在某处传递 std::future
,并通过 write_release()
销毁来履行承诺。但这只是我的含糊其辞)。
这是一个使用 std::queue
并在 C++11 及更高版本中工作的替代方法:
#include <queue>
void test(stream<float> &fifo) {
std::queue<stream_wslot> wslots;
#if __cplusplus >= 201703L // C++17 and later:
auto& even = wslots.emplace(fifo);
auto& odd = wslots.emplace(fifo);
#else // C++11 and C++14:
auto& even = (wslots.emplace(fifo), wslots.front());
auto& odd = (wslots.emplace(fifo), wslots.front());
#endif
// work with even and odd ...
}
首先创建 even
引用的元素,然后创建 odd
引用的元素。
作用域结束时,std::queue
先释放even
引用的元素,然后释放odd
引用的元素。
RAII 非常舒适,我很难为资源提供等效设计,这些资源必须按照获取它们的顺序(FIFO)释放,而不是按照自然产生的相反顺序(堆栈)释放RAII.
在我的具体情况下,我有一个 stream
class 如下:
template<typename T>
class stream {
...
public:
// Producer API
T& write_acquire(); // This acquires a storage element and will "block"
// until a slot is available in the underlying resource
void write_release(&T); // This releases the storage element, transferring the data to a consumer
// Consumer API
T& read_acquire(); // This acquires a storage element and will "block"
// until a slot has been write_release
void read_release(&T); // This releases the storage element making it available
// for a potential future write_acquire
};
我正在考虑提供一个 RAII 风格的助手:
template<typename T>
class stream_wslot {
stream<T> &s;
T &slot;
public:
stream_wslot(stream<T> &s) : s{s}, slot{s.write_acquire()} {}
~stream_wslot() { s.write_release(slot); }
operator T&() { return slot; }
T& operator=(T &val) { return slot = val; }
};
但问题是以下用法将无法正常运行:
void test(stream<float> &fifo) {
stream_wslot even(fifo);
stream_wslot odd(fifo);
... first ...
... second ...
// releases odd !!!
// releases even
}
即先释放odd
槽,再释放even
槽。虽然我可以在 stream
中添加一个 "reordering" 队列,但我想知道是否有一种 "clean" 方法可以将 RAII 推广到这些情况。
使用 std::optional
,成本非常适中,最小的开销提供了对构建的更多控制,以及定义明确的销毁顺序。这正是您要找的,在这里。
例如:
std::optional<stream_wslot> o_even;
std::optional<stream_wslot> o_odd;
o_odd.emplace(fifo);
o_even.emplace(fifo);
auto &even=*o_even;
auto &odd=*o_odd;
从现在开始,使用 odd
和 even
的现有代码将很难区分。总计:odd
首先构建,even
第二构建。 odd
首先被销毁,当离开这个范围时, even
第二个被销毁。相同有效的构造和销毁顺序。
您可以在另一个线程上有一个队列 运行 以异步实现 FIFO 逻辑。如果 wslot
对象是使用对该队列的引用构造的,它们可以告诉它在它们析构时为它们执行 write_release()
,但在构造时执行常规 write_acquire()
,这将在必要时阻塞.
(或者,在构建时,他们可以在某处传递 std::future
,并通过 write_release()
销毁来履行承诺。但这只是我的含糊其辞)。
这是一个使用 std::queue
并在 C++11 及更高版本中工作的替代方法:
#include <queue>
void test(stream<float> &fifo) {
std::queue<stream_wslot> wslots;
#if __cplusplus >= 201703L // C++17 and later:
auto& even = wslots.emplace(fifo);
auto& odd = wslots.emplace(fifo);
#else // C++11 and C++14:
auto& even = (wslots.emplace(fifo), wslots.front());
auto& odd = (wslots.emplace(fifo), wslots.front());
#endif
// work with even and odd ...
}
首先创建 even
引用的元素,然后创建 odd
引用的元素。
作用域结束时,std::queue
先释放even
引用的元素,然后释放odd
引用的元素。