✅ Cancel stream read
I'm running a Task that constantly reads some data off a (named pipe) stream when it's present.
the
_shouldRun
indicates whether the task should continue, I set this to false
when it needs to stop
The issue is that the read operation on the stream is infinitely blocking, so I'm never sure if my Task will end properly
Can I stop a blocking stream read operation from another thread in some way?82 Replies
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Fair enough, but how do I use
BinaryReader
with a CancellationToken
?
afaik that's not really a thingUnknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Oh, does that directly work with async/await?
I thought it was a user-implemented thing, mb
??
As I read from other sources online it is a user implemented thing
Since I cannot supply a CancellationToken to
reader.ReadUInt16()
or any of those methods, I can't implement it properly
e.g. this answer tells that you should check if a cancellation was requested in the loop (manually)
which would have the same effect as using a boolean, because any read operation would still block and the token not checked until the read operation finishes
So the issue is that nothing in BinaryReader
accepts a CancellationToken
TeBeCo
you would have the CancellationToken which holds a boolean on the cancellation being requested or not
Quoted by
<@689473681302224947> from #Cancel stream read (click here)
React with ❌ to remove this embed.
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
so there is no non-blocking API similar to BinaryReader?
I have a long-running task with a loop that constantly reads from a messaging stream and invokes an event when a message is ready for handling
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
how can I while using BinaryReader tho
it has no methods accepting a cancellationtoken or anything
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
This is the method that blocks until a message is available
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
:\
hmm idk if I can with this
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
since they're pipestreams
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I'm not just gonna
async
everything
I'm kinda new to C#
But I don't think that's the right approachUnknown User•12mo ago
Message Not Public
Sign In & Join Server To View
yeah It'll just wait
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I didn't know how to solve that really
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I can work around BinaryReader here I guess
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
lol okay- yeah
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
(Contains example for Socket
TCP Echo
)
https://devblogs.microsoft.com/dotnet/system-io-pipelines-high-performance-io-in-net/
https://docs.microsoft.com/en-us/dotnet/standard/io/pipelines
if you're handling data from/to a stream, and dealing with intermediate buffer / parser / writer, you probably should consider using System.IO.Pipelines
It's handling internally
* temporary buffer
* memory pool to re-use memory and avoid allocation
* accumulate buffer until you decide you have enough data to do something (deserialize ?)
There's dedicated extensions for Stream
for specific use case like :
(Contains a sample to read file / dump to console)
Reading (eg: to a file):
Writing (eg: to Console):
No that's fine lol
I'll work around binaryreader
so if I use this, I would pass a
ct
as a parameter to my method, and then pass that same ct
to the ReadAsync method?Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
hehe that's a bit primitive if you ask me
but fair enough, it's a stream
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
ah yes the function won't return normally ofc
okay
reasonable
ok so then
This is the action method that is run with a Task
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
So is it still a good idea to run it in a Task like that?
With async await in that case
so my run method would also be async
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
It's just
Task.Run(RunAsync)
then
that accepts async methods
as overload
wait nvm
Hmm what happens with the CancellationToken that can be passed to a task?
Can I access that somehow in the running method without accessing an instance variable?
Currently I have this
Which is a little messy with the cancellationTokenSource just floating around and being passed to the task
Is there some way to improve that?Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
TeBeCo
might be a
Task.Run(async () => await RunAsync());
Quoted by
<@689473681302224947> from #Cancel stream read (click here)
React with ❌ to remove this embed.
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
mkay
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Hey, I implemented my reading logic like this:
It seems that triggering the cancellation does not immediately stop the ReadAsync action though
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
100% sure for named pipe stream?
It only seems to trigger after closing the connected client
I have a client that just connects and sends nothing
I created a cancellationtoken with a timeout of 2 seconds
I start receiving the message in a 'Loaded' (async) event handler from my WPF window
The prefixed (
[NORMAL]
and such) log entries are from my client application which runs as child
When I close the app normally, after waiting for a bit for the 2 seconds to pass, it doesn't throw at all
When I close my client, which disconnects the pipe client, it runs until the second ReadAsync
and then cancels
it prints Collecting message data...
and then throws
intermediary receive methods that eventually call the CollectMessage method
Fuck
Hold on
Heh? nvmUnknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I though I made a mistake because I forgot to set the pipe to async
with
PipeOptions.Asynchronous
but it still doesn't work
this is my pipe server new NamedPipeServerStream(Constants.PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
I'm starting to believe that PipeStream just doesn't support async reading
but it does say 'and monitors cancellation requests'Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
no worries, I'm patient ^-^
Also I think it doesn't actually support cancelling while reading
From looking at the source of stream you can see that the token doesn't get passed to the read operation at all, only checked before reading:
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
This is from the
Stream
class
and PipeStream
doesn't override itUnknown User•12mo ago
Message Not Public
Sign In & Join Server To View
neither overrides it
NamedPipeServerStream extends PipeStream extends Stream
so my stream uses that same implementation from what I can see
meaning the cancellation token just gets ignored
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
wooooh I hadn't seen this one
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I removed the new task usage yeah
maybe they forgot the Task.Start
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
that's an event handler...
oh well nvm
that was an event handler
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I moved it to a method so I can adjust this yeah
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Why
heh
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
right, I'll fix that
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
fair but that's a bit complex
yeah
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
what I have here is just a testing HMI for my communication code
which will be implemented better in the actual product
but ok that's not the cause of my issue right
hmm okay the readpipeasync might fix it
with the Task.Run ofc
Doesn't work
doesn't throw after 2 seconds
implemented like this
It does get to the debug message
And then fails to ever end the read
Ok, I have it working now
Using the
CancelIoEx
method instead
from the answer below
It cancels correctly after 2 seconds and the OperationCancelledException gets thrown as unhandled in user code
Follow up question, why does it say unhandled when I'm catching it?Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I did in my even handler
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Yes, I'm logging something when it catches:
But before that it shows up as unhandled
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
Yeah I don't have to pass it
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
I think I'm printing some detail..
But it shouldn't say exception unhandled right?
Or is that because it goes through the Task binary
Unknown User•12mo ago
Message Not Public
Sign In & Join Server To View
aight, you've helped a lot already 😅, tysm! It's working now + you gave great feedback on some bad habits
Good luck with work, I'll figure it out