Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync blocks and library helper tasks #16424

Open
mppf opened this issue Sep 19, 2020 · 1 comment
Open

sync blocks and library helper tasks #16424

mppf opened this issue Sep 19, 2020 · 1 comment

Comments

@mppf
Copy link
Member

mppf commented Sep 19, 2020

If a library uses begin to create a helper task, wrapping the library call in sync will lead to a hang.

(Issue #16387 discusses approaches to a similar problem with serial).

Consider a library that - somewhere deep inside a call - needs to create a task in order to function correctly. For example, it might need to create some kind of helper task like a progress thread. If the program calling the library makes the call within a sync block, then the call will never complete (because the helper task will be waiting for more work). We could say that the sync block shouldn't be used if such functions are called - but that property is hard to see when the sync block function calls to libraries and the helper task might be deep within those. Would documentation for all library functions need to include a note about whether or not it is safe to call the function in a sync block?

I know of two strategies to resolve this:

A. Create a task team idea - which, in a way, is like naming the sync block so it can be stored in a variable and tasks can be created that track termination with a variable instead of the sync block.
B. Provide a mechanism to de-register a task with the currently enclosing sync block and instead register it with the outemost one (which is checked at the end of main). This approach is sortof like disown in bash.

@bradcray
Copy link
Member

For the historical perspective: This was pointed out, much to our embarrassment, in the first SC tutorial we did on Chapel. We'd always imagined taking approach A to address it (since task teams had other value-adds and use cases as well, like supporting eurekas, or task-based collectives), but then have never been able to prioritize task teams properly after some initial design discussions. Option B is intriguing as well, though, and has the advantage of being a less significant, if more specialized change (in the sense that it doesn't seem like it would lead to other obvious benefits).

Option A seems like it could also be applicable to the issue brought up in #16387 about serial statements and libraries in that serial and sync could be applied to a given team or the global team by default, but a library could create a new disjoint "daemons" team that wouldn't be subject to the enclosing serial/sync unless it could name that team. Whereas option B seems like it would require some other semantic overlay to say "and always create me no matter what" unless we decided the mechanism implied that too (where we could say something like begin daemon or begin orphan gave both behaviors.

One other advantage to option B is that it seems like it could be a common problem to have a program hang because nobody ever got around to shutting down the daemon/orphan tasks by calling the library's finalize() routine. But perhaps the termination detection for the program could realize that all remaining tasks were daemons/orphans (by maintaining a distinct end count for them and checking it when the user's endcount got to 0) and print out a nice warning/error and then exit rather than just deadlocking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants