Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I agree that <code>delete this</code> is a code smell, and to a lesser extent <code>delete</code> on its own. But I think that here it is a natural part of continuation-passing style, which (to me) is itself something of a code smell.</p> <p>The root problem is that the design of this API assumes unbounded control-flow: it acknowledges that the caller is interested in what happens when the call completes, but signals that completion via an arbitrarily-complex callback rather than simply returning from a synchronous call. Better to structure it synchronously and let the caller determine an appropriate parallelization and memory-management regime:</p> <pre><code>class Worker { public: void DoWork(ArgT arg) { // Async1 is a mistake; fix it later. For now, synchronize explicitly. Latch async_done(1); Async1(&lt;args&gt;, [&amp;]() { async_done.count_down(); }); async_done.await(); Latch parallel_done(2); RunParallel([&amp;]() { DoStuff(&lt;args&gt;); parallel_done.count_down(); }); RunParallel([&amp;]() { DoStuff(&lt;other_args&gt;); parallel_done.count_down(); }; parallel_done.await(); } }; </code></pre> <p>On the caller-side, it might look something like this:</p> <pre><code>Latch latch(tasks.size()); for (auto&amp; task : tasks) { RunParallel([=]() { DoWork(&lt;args&gt;); latch.count_down(); }); } latch.await(); </code></pre> <p>Where RunParallel can use std::thread or whatever other mechanism you like for dispatching parallel events.</p> <p>The advantage of this approach is that object lifetimes are much simpler. The ArgT object lives for exactly the scope of the DoWork call. The arguments to DoWork live exactly as long as the closures containing them. This also makes it much easier to add return-values (such as error codes) to DoWork calls: the caller can just switch from a latch to a thread-safe queue and read the results as they complete.</p> <p>The disadvantage of this approach is that it requires actual threading, not just boost::asio::io_service. (For example, the RunParallel calls within DoWork() can't block on waiting for the RunParallel calls from the caller side to return.) So you either have to structure your code into strictly-hierarchical thread pools, or you have to allow a potentially-unbounded number of threads.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload