Problem with multiple std :: thread and main program execution

Every day I fight for the mechanism of launching several timers and do not synchronize the main execution of the program. Combinations of .join() and .detach() , wait_until() , etc.

I have a std::thread vector and I want:

  • complete the first position
  • wait for the end
  • perform the next position
  • wait for the end

while the rest of my application is running, users click on things, etc. Everything I came up with looks like:

  • blocks the start of the main program while the timers go

or

  • disconnects from the main thread, but then the timers start at the same time, as I want one after the previous one.

I even posted: C ++ 11 std :: threads and is waiting for the threads to finish , but it does not have permission, which may seem useful to me.

Should I use std::launch::async maybe?

EDIT: I'm not sure why it's so hard for me to understand. I mean, video games do this all the time. Take the Tiny Tower, for example. You stock up your floors, and each of these operations has a delay from the moment the stock is launched until this product is stocked up, and it calls up the HUD pop-up window and says: β€œThe floor is now patented.” Meanwhile, the whole game remains running for you to do other things. I have to be tight because I cannot understand this.

+4
source share
2 answers

This piece of code will perform std::vector zero tasks in a separate thread.

 typedef std::vector<std::function< void() >> task_list; typedef std::chrono::high_resolution_clock::duration timing; typedef std::vector< timing > timing_result; timing_result do_tasks( task_list list ) { timing_result retval; for (auto&& task: list) { std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); task(); std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); retval.push_back( end-start ); } return retval; } std::future<timing_result> execute_tasks_in_order_elsewhere( task_list list ) { return std::async( std::launch::async, do_tasks, std::move(list) ); } 

this should start each of the tasks sequentially outside the main thread and return std::future , which contains the synchronization results.

If you want temporary results to produce smaller fragments (i.e. before they were all ready), you will have to work harder. I would start with std::packaged_task and return std::vector<std::future< timing >> and from there.

The above code is untested / not compiled, but should not have fundamental flaws.

You will notice that the above does not use std::thread . std::thread is a low-level tool on which you should create tools from above, and not something that you should use directly (it is rather fragile due to the requirement that it be join ed or detach ed before destruction, among other things) .

While std::async nothing to write home, this is great for fast and messy multithreading, where you want to do a sequential task and do it "somewhere else." The lack of decent signaling via std::future makes it less complete (and this is the reason you might need to write higher level abstractions around std::thread ).

Here is one of them that will run a task sequence with a minimum delay between them:

 #include <chrono> #include <iostream> #include <vector> #include <functional> #include <thread> #include <future> typedef std::chrono::high_resolution_clock::duration duration; typedef std::chrono::high_resolution_clock::time_point time_point; typedef std::vector<std::pair<duration, std::function< void() >>> delayed_task_list; void do_delayed_tasks( delayed_task_list list ) { time_point start = std::chrono::high_resolution_clock::now(); time_point last = start; for (auto&& task: list) { time_point next = last + task.first; duration wait_for = next - std::chrono::high_resolution_clock::now(); std::this_thread::sleep_for( wait_for ); task.second(); last = next; } } std::future<void> execute_delayed_tasks_in_order_elsewhere( delayed_task_list list ) { return std::async( std::launch::async, do_delayed_tasks, std::move(list) ); } int main() { delayed_task_list meh; meh.emplace_back( duration(), []{ std::cout << "hello world\n"; } ); std::future<void> f = execute_delayed_tasks_in_order_elsewhere( meh ); f.wait(); // wait for the task list to complete: you can instead store the `future` } 

which the auxiliary async sleep thread should do for (at least as long as) the durations that you use before starting each task. As it is written, the time taken to complete each task is not taken into account with respect to delays, therefore, if tasks take longer than delays, you will ultimately complete tasks that are performed without delay between them. A change that should be easy if you want.

+4
source

Your problem is understandable, because what you need in order to have timers that do not block the event loop is an event loop, and C ++ does not yet have a standard one. You need to use other frameworks (such as Qt, Boost.Asio (?) Or non-portable APIs (select (), etc.)) to record event loops.

0
source

Source: https://habr.com/ru/post/1496045/


All Articles