Some background: my C# code calls into some unmanaged code (C++) that does a blocking wait. The blocking wait, however, is alertable (like Thread.Sleep
- I suppose it calls WaitForSingleObjectEx
with bAlertable TRUE
under the cover); I know for sure it is alertable, as it can be "waked up" by QueueUserAPC
.
If I could simply use managed Threads, I would just call the blocking method, and then use Thread.Interrupt
to "wake" the thread when I need it to exit; something like this:
void ThreadFunc() {
try {
Message message;
comObject.GetMessage(out message);
//....
}
catch (ThreadInterruptedException) {
// We need to exit
return;
}
}
var t - new Thread(ThreadFunc);
//....
t.Interrupt();
(NOTE: I am not using this code, but it is something that, to the top of my knowledge, could work for this peculiar situation (alertable wait in unmanaged code out of my control). What I'm looking for is the best equivalent (or a better alternative!) to this in TPL).
But I have to use the TPL (Tasks instead of managed Threads), and the unmanaged method is out of my control (I cannot modify it to call WaitForMultipleObjectEx
and make it return when I signal en Event, for example).
I am looking for a Thread.Interrupt
equivalent for Tasks (something that will post an APC on the underlying thread). AFAIK, CancellationTokens require the code to be "Task aware", and do not use this technique, but I'm not sure: what happens, I wonder, if a task does a Thread.Sleep
(I know there is a Task.Wait
, but it's just for having an example of a non-task wait which is alertable), can it be cancelled?
Is my assumption wrong (I mean, could I just use a CT and everything will work? But how?).
If there is no such method... I'm open to suggestions. I'd really like to avoid to mix Threads and Tasks, or use P/Invoke, but if there is no other way, I would still like to do it in the "cleanest" way possible (which means: no rude aborts, and something "Tasky" :) )
Edit:
For those who are curious, I have "confirmed" that Thread.Interrupt could work in my case because it calls QueueUserAPC
.
It calls InterruptInternal
, then Thread::UserInterrupt
, then Alert
, which queues the APC. It is actually quite clever, as it allows you to sleep/wait and then wake a thread without the need to use another synchronization primitive.
I just need to find a TPL primitive that follows the same flow