提问人:nevermind 提问时间:7/23/2023 最后编辑:prapinnevermind 更新时间:7/27/2023 访问量:63
如何检查线程的“共享状态”或“内存状态”的详细状态?如何不调用std::async( )块?
How to check the verbose status of a thread's "shared state" or "memory state"? How to not make calls to std::async( ) block?
问:
我使用多线程的方法是:
typedef std::pair<std::vector<char>, int> PATH_PAIR;
std::list<PATH_PAIR>
TSP::return_all_paths_list(
PATH_PAIR parent_path_pair,
std::list<char> unvisited_cities
) {
std::list<PATH_PAIR> subseq_paths_list;
std::vector<std::future<std::list<PATH_PAIR>>> future_vec;
if (unvisited_cities.empty()) { // END RECURSION
// NON-REALTED CODE
return subseq_paths_list;
}
for (const char curr_city: unvisited_cities) { // DO RECURSION
PATH_PAIR new_path_pair_addr = parent_path_pair;
std::list<char> subseq_unvisited_cities = unvisited_cities;
std::future<std::list<PATH_PAIR>> returned_path_list_future;
// NON-RELATED CODE
returned_path_list_future = std::move(std::async(std::launch::async, return_all_paths_list, this, new_path_pair_addr, subseq_unvisited_cities));
future_vec.push_back(returned_path_list_future);
}
while (!future_vec.empty()) { // GET-VALUES-WHILE
for (std::future<std::list<PATH_PAIR>>& curr_future : future_vec) // GET-VALUES-FOR
if (curr_future.valid()) {
subseq_paths_list.merge(curr_future.get());
}
// future_list.remove_if(
// [] (std::future<std::list<PATH_PAIR>> input_future) -> bool {
// return !input_future.valid();
// }
// );
}
return subseq_paths_list;
}
我有几个问题:
-
如果从 std::async 获取的 std::future 未从引用中移动或绑定到引用,则 std::future 的析构函数将在完整表达式的末尾阻塞,直到异步操作完成,实质上使代码(如以下代码)同步:
std::async(std::launch::async, []{ f(); }); // temporary's dtor waits for f() std::async(std::launch::async, []{ g(); }); // does not start until f() completes
a. “移自”和“绑定到参考”这两个词是什么意思?
b. 将调用包装在 an 中是否会使调用在循环的后续迭代中不阻塞?
c. 或者上述两行中的调用是否仅仅因为使用了 lambda 而阻塞?std::async
std::move
std::async
// DO RECURSION
如何检查共享状态是否已准备就绪?
a.a. 对 (和 ) 的调用会阻止,直到共享状态准备就绪。问题是,我不想等待。我想检查共享状态是否已准备就绪,如果没有,我想继续下一个对象。我该怎么做? 仅检查共享状态是否与对象关联。
b. 此外,根据 cppreference std::async,调用的返回值为:std::future::wait
std::future::get
std::future
std::future::valid
std::async
std::future 是指此调用创建的共享状态
std::async
因此,在循环中,如果对它进行调用,则获取的将始终返回(前提是尚未对它进行调用)。如果我在调用 an 后删除,则不必检查对象的有效性。但是,我尝试过的删除元素 STL 方法都不起作用,编译时错误大约是显示器高度的两倍。
//GET VALUES
std::future
true
std::future::valid
std::future::get
std::future
std::future::get
std::future
我想,也许调用除了释放共享状态之外还会破坏对象,但是我写了一段小测试代码:
std::future::get
int mul2(int x) {return x << 1; } int main() { std::vector<std::future<int>> fut_vec; for (int i = 0; i < 5; i++) { fut_vec.push_back(std::move(std::async(std::launch::async, mul2, i))); } for (std::vector<std::future<int>>::iterator itr = fut_vec.begin(); itr != fut_vec.end(); itr++) { if (itr->valid()) { std::cout << "Value: " << itr->get() << " | No. of vec elements(futures): " << fut_vec.size() << std::endl; } } return 0; }
显示 总是返回相同的整数。
fut_vec.size()
如何销毁对象?
std::future
我最近开始接触多线程,所以现在我正在尝试使用多线程来实现旅行推销员问题。
答:
要检查未来的共享状态是否已准备就绪,请等待 0 秒。如果它准备好了,它就会这么说;否则,它将超时。
std 异步返回 future 的阻塞行为将传递给您将其移动到的任何位置。阻止行为处于共享状态,而不是返回的特定将来。
销毁对象与多线程问题无关。
你必须保留从 std async 返回的 futures,直到你知道任务已经完成,然后你可以销毁它们。如果你提前销毁它们,你将阻止任务完成。
通常,创建无限数量的并行线程对任何程序来说都是一个糟糕的计划。典型的并行代码会创建一个要处理的任务池,然后使用线程池来处理这些任务。
直接创建线程(或者通过 std::thread 或 std::async)并给它一个任务来处理,这有点像手动管理内存。当然,它可以解决问题,但这不是最佳实践。
...
我要做的是创建一个使用 和 的线程安全队列。添加方法、 。T
std::condition_variable
std::mutex
std::deque
push
pop
然后我会创建一个线程池。线程池拥有 的线程安全队列。它有一个方法。与未来不同的是,这个未来不会阻止毁灭。std::packaged_task<void>
std::future<void> start_task( std::function<void()> )
std::async
线程池维护 (hardware_concurrency_count) 个线程,无论是 还是已创建,每个线程都会从线程安全队列中弹出一个任务,执行该任务,然后重复。std::thread
std::async
也许在你的 中添加一个,以及一个 .wait_until_all_tasks_done
threadpool
terminate_all_tasks
您可以在 TSP 问题之外为线程安全队列和线程池编写单元测试,然后使用这两个基元解决 TSP,而不必同时处理有缺陷的线程代码。
评论
std::future<T>::wait_for
和std::future<T>::wait_until
fut_vec
fut_vec
std::future
wait_for(0s)