In the case that a user creates a bunch of threads and main() exits without calling join() on those threads, we must delay backend destruction so that those other threads can finish their work and cleanup via thread_local ctor/dtor sequence.
Otherwise, it's possible that the main thread will attempt to destroy the device and context handles while they're still being used by other detached threads.
This case is an example of a bad program since main thread should call join() but it's best if we handle it more gracefully than let it segfault.
Add a test
Refactor using atomic operations in thread_local chipstar::Queue ctor/dtor
In the case that a user creates a bunch of threads and main() exits without calling join() on those threads, we must delay backend destruction so that those other threads can finish their work and cleanup via thread_local ctor/dtor sequence.
Otherwise, it's possible that the main thread will attempt to destroy the device and context handles while they're still being used by other detached threads.
This case is an example of a bad program since main thread should call join() but it's best if we handle it more gracefully than let it segfault.
chipstar::Queue
ctor/dtor