Open SeverTopan opened 6 years ago
This makes the use of PPLX pretty difficult for any long-running program. A simple analogy would be if the only way to receive a notification was to subscribe to an event ... but you can't ever unsubscribe. And, because tasks are not differentiable, you don't even know if you've already subscribed to this event or not, so you just keep subscribing and adding to runtime memory.
Description
PPLX tasks will only be invoked as soon as their antecedents complete, even in the case of cancellation. Consider the task chain A > B > C. Once B is cancelled, C will only execute once A completes. As consequence, B's and C's lambda will remain allocated until A completes. This behaviour leads to two issues:
The memory leaking problem especially manifests itself in the implementation of
when_any
.when_any
seems to append continuations to all tasks passed into it which sets a task completion event once the first one completes and cancels the continuations all the other tasks. If one were to callwhen_any
inside a loop, long running tasks can find themselves with many cancelled yet non-deallocated continuations.Simple Example
When run, we observe
At this point,
val
has been created and passed to the continuation of the task by capture.val
has left its scope, and the continuation to thecreate_task
has been cancelled, but the execution hangs onstd::cin
. Since the continuation has been cancelled, it will not run, and theval
that was captured cannot be accessed, however, note that we have not seen "test class 0 destructed" yet. This only occurs oncestd::cin
is triggered:The fact that cancelled continuations do not deallocate their contents can cause memory leak conditions if a set of tasks added as continuations onto a long-running antecedent. Even if elements are cancelled, the tasks will not be destructed until the antecedent runs to completion. This can cause major leaks with certain task design patterns.