是否有可能阻止一组锁定/期货/任何可阻止的实体,直到其中任何一个准备就绪?我们的想法是:
std::vector<std::future<T>> futures = ...;
auto ready_future = wait_until_an_element_is_ready(futures);
process(ready_future.get());
我记得像libevent,libev和libuv这样的库具有IO任务的这种能力。但我不知道这些是否可以用于锁/期货。
我想到的一种方法就是让期货在完成后调用处理程序,但同时将处理程序比较并交换为null,以便其他期货不能调用它。然而,这需要协调期货,因此无法对锁进行。
更新: C ++ 2x似乎有proposal。
答案 0 :(得分:6)
如果您有可用的增强功能,其线程功能远远超过标准库。
这将是在c ++ 17之后的情况,以及事物的外观,即使在c ++ 20之后。
{{1}}
答案 1 :(得分:0)
现在,这是不可能的,你可以通过编写自己的查找逻辑来解决它。
template<typename Iterator>
Iterator find_first_ready_future(Iterator begin, Iterator end)
{
return std::find_if(begin, end, [](auto &future) { return future.wait_for(0s) == std::future_status::ready; }
}
template<typename T>
std::future<T> wait_until_an_element_is_ready(std::vector<std::future<T>> &vector)
{
assert(!vector.empty());
auto iterator = vector.end();
do
{
// force switch of threads (if you don't want a busy loop, you might want to sleep this thread)
// If reaction speed is very important, you might want to skip this first yield/sleep in the first iteration.
std::this_thread::yield();
iterator = find_first_ready_future(vector.begin(), vector.end());
} while (iterator == vector.cend());
auto result = std::move(*iterator);
vector.erase(iterator); // Remove the ready future to prepare for the next call. (You ain't allowed to call .get() twice)
return result;
}
请注意,所有期货都必须使用'async'标志创建,因为如果'延迟',这将成为无限循环。
PS:如果你不想让你的主线程阻塞,你可能想在自己的线程/未来执行它。
另一种选择是包装你的期货来执行任务。这有点类似于future.then
提案:
template<typename T>
std::vector<std::future<void>> executeOnComplete(std::vector<std::future<T>> &&v)
{
std::vector<std::future<void>> result;
result.reserve(v.size());
for (auto &f : v)
result.emplace(std::async(std::launch::async,
[f = std::move(f)] { process(f.get()); }));
return result;
}
此替代方案为每个未来创建一个新线程,并将阻止它直到原始未来准备就绪。它带来了创建太多线程的风险。
PS:有了一些花哨的result_of
模板逻辑,你甚至可以创建返回`process