Proper closing application with FileStream.Read - c#

In some place I call
Task.Run(new Action(Read));
this call starts task in other thread:
private void Read()
{
while (!cancelToken.IsCancellationRequested)
{
int bytesReaded = deviceStream.Read(buffer, 0, bufferSize);
}
}
This thread blocks while Read try to get some data from file (this is not usual file, this is device). then I close application, form closed, but application still runing. I tried Close and Dispose on deviceStream but not helped - its still wait to Read completed. Interrupting thread not recommended by Microsoft.
The main goal is read data non-stop, but data arrives from device by pieces, and pause between pieces can be huge, so Read can be blocked for the long time.
Questions: Is there some method to gracefully interrupt Read? Is there another pattern can be implemented to achieve my goal (with BeginRead/EndRead maybe, but readed here that EndRead also blocks and can't be interrupted.
PS: I see new method in MSDN ReadAsync, but can't imagine how I can use it (there I need restart Read)

You can you a ReadTimeout property if the device stream provides it:
https://msdn.microsoft.com/en-us/library/system.io.stream.readtimeout%28v=vs.110%29.aspx

It was not FileStream.Read issue, I blocked ReadDispatcher in driver using KeWait... function.

Maybe it`s helpful for you:
private void Read()
{
while (!cancelToken.IsCancellationRequested)
{
if(deviceStream.CanRead && deviceStream.Length > 0)
int bytesReaded = deviceStream.Read(buffer, 0, Math.Min(bufferSize, deviceStream.Length));
}
}
Of course when you dispose you need call cancel request

Related

How do I continue to read data from ReadAsync after I start processing the data?

I am new here and by no means an expert at c# programming.
I am writing an application that connects to a device over TCP. It sends the device a command and the device responds. Sometimes The device will send another message after it has responded to my command. For example if I say "Read Tag" It will respond with the tag value "Tag: abcdefg". But sometimes, after a couple of hundred milliseconds, it will respond with something like "Buffer Low: 14" telling me the size of its buffer.
Here is how I am currently receiving data:
public Task<string> ReceiveDataAsync()
{
receiveBuffer = new byte[receiveBufferSize];
Task<int> streamTask = _networkstream.ReadAsync(receiveBuffer, 0, receiveBufferSize);
// Since the read is async and data arrival is unknown, the event
// must sit around until there is something to be raised.
var resultTask = streamTask.ContinueWith<String>(antecedent =>
{
Array.Resize(ref receiveBuffer, streamTask.Result); // resize the result to the size of the data that was returned
var result = Encoding.ASCII.GetString(receiveBuffer);
OnDataReceived(new TCPEventArgs(result));
return result;
});
return resultTask;
}
I am confused about reading the network stream. When I use the ReadAsync method, and then I get something back, how do I handle the delay? In my mind, I get the first response of the tag data, then I start to work on that task. Even though I work on the task ".ContinueWith" will my stream continue to receive data? Will the task automatically go back and process more data as it comes in the stream? Do I need to call the ReceiveDataAsync method every time I think some data should be arriving or will it remain open until Dispose of the stream?
Yes, you need to call ReceiveDataAsync repeatedly, usually call it in callback of ContinueWith, or just put it in a loop if you use async/await, so that you read some data, process it and then go back to read (or wait) the next bytes.
Like this:
private static void OnContinuationAction(Task<string> text)
{
Console.WriteLine(text);
ReceiveDataAsync().ContinueWith(OnContinuationAction);
}
...
ReceiveDataAsync().ContinueWith(OnContinuationAction);
Or with async/await:
private async void ReceiveDataContinuously()
{
while(true)
{
var text = await ReceiveDataAsync();
Console.WriteLine(text);
}
}
If you don't call ReadAsync on the stream repeatedly, as long as the underlying TCP connection is open it will continue receiving data into the buffer, but your program cannot get them.

C# Named Pipes, how to detect a client disconnecting

My current named pipe implementation reads like this:
while (true)
{
byte[] data = new byte[256];
int amount = pipe.Read(data, 0, data.Length);
if (amount <= 0)
{
// i was expecting it to go here when a client disconnects but it doesnt
break;
}
// do relevant stuff with the data
}
how can I correctly detect when a client disconnects?
Set a read timeout and poll the NamedPipeClientStream.IsConnected flag when a timeout occurs.
A Read Timeout will cause reads that are idle for the timeout duration to throw InvalidOperationException
If you are not reading, and want to detect disconnections, call this method on a worker thread for the lifetime of your pipe connection.
while(pipe.IsConnected && !isPipeStopped) //use a flag so that you can manually stop this thread
{
System.Threading.Thread.Current.Sleep(500);
}
if(!pipe.IsConnected)
{
//pipe disconnected
NotifyOfDisconnect();
}
One easy way to tell if your pipe has been broken (remotely) is to always use asynchronous reads instead of sync ones, and to always have at least one read submitted asynchronously. That is, for every successful read you get, post another async read, whether you intend to read another or not. If you close the pipe, or the remote end closes it, you'll see the async read complete, but with a null read size. You can use this to detect a pipe disconnection. Unfortunately, the pipe will still show IsConnected, and you still need to manually close it, I think, but it does allow you to detect when something went wonky.
Use WaitForPipeDrain() method after Writing to the Pipe (using WriteByte() or Write()) and catch the exception which is "Pipe is Broken".
You may want to put that in a while loop and keep writing to the pipe.
in the case of Synchronous call you track the -1 return by ReadByte of Stream abstract class, which is inherited by NamedPipeServerStream:
var _pipeServer = new NamedPipeServerStream(PipeConst._PIPE_NAME, PipeDirection.InOut);
int firstByte = _pipeServer.ReadByte();
const int END_OF_STREAM = -1;
if (firstByte == END_OF_STREAM)
{
return null;
}
The docs states indeed:
//
// Summary:
// Reads a byte from a pipe.
//
// Returns:
// The byte, cast to System.Int32, or -1 indicates the end of the stream (the pipe
// has been closed).
public override int ReadByte();
Only after a first failed read your IsConnected property will be correctly set to false:
_pipeServer.IsConnected
You might observe that even on the
official illustration of Microsoft (and more precisely in the StreamString class)
this check is not done:
Do not forget to Vote for this answer and visit my Youtube channel. More info on my profile.
Regards !

Nonblocking io using BinaryWriter to write to usblp0

I'm doing a program in c# (mono) to print to a fiscal printer (escpos) and it works okay. The problem is that when I print, the program hangs until the buffer I have is cleared. So, as you imagine if I print a couple of images it gets bigger and so it hangs for a while. This is not desirable. I have tested in 2 ways
One way:
BinaryWriter outBuffer;
this.outBuffer = new BinaryWriter(new FileStream (this.portName,System.IO.FileMode.Open));
.... apend bytes to buffer...
IAsyncResult asyncResult = null;
asyncResult = outBuffer.BaseStream.BeginWrite(buffer,offset,count,null,null);
asyncResult.AsyncWaitHandle.WaitOne(100);
outBuffer.BaseStream.EndWrite(asyncResult); // Last step to the 'write'.
if (!asyncResult.IsCompleted) // Make sure the write really completed.
{
throw new IOException("Writte to printer failed.");
}
second Way:
BinaryWriter outBuffer;
this.outBuffer = new BinaryWriter(new FileStream (this.portName,System.IO.FileMode.Open));
.... apend bytes to buffer...
outBuffer.Write(buffer, 0, buffer.Length);
and neither method is allowing the program to continue the execution. Example: if it starts to print and paper is out it will hang until the printer resumes printing which is not the right way.
Thanks in advance for your time and patience.
The problem is that you're making the program wait for the write to complete. If you want it to happen asynchronously, then you need to provide a callback method that will be called when the write is done. For example:
asyncResult = outBuffer.BaseStream.BeginWrite(buffer,offset,count,WriteCallback,outBuffer);
private void WriteCallback(IAsyncResult ar)
{
var buff = (BinaryWriter)ar.AsyncState;
// following will throw an exception if there was an error
var bytesWritten = buff.BaseStream.EndWrite(ar);
// do whatever you need to do to notify the program that the write completed.
}
That's one way to do it. You should read up on the Asynchronous Programming Model for other options, and pick the one that best suits your needs.
You can also use the Task Parallel Library, which might be a better fit.

C# "using" SerialPort transmit with data loss

I'm new to this forum, and I have a question that has been bothering me for a while.
My setup is a serial enabled character display connected to my pc with a usb/uart converter. I'm transmitting bytes to the display via the serialPort class in a separate write buffer thread in a C++ style:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
s.Write(b,0,b.Length);
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
Assuming the serial port is already opened, this works perfectly and transmits all the data to the display. There are though no exception handling at all in this snippet. Therefore I was looking into implementing a typical C# feature, the 'using' statement and only opening the port when needed, like so:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
using(s){ //using the serialPort
s.Open();
s.Write(b,0,b.Length);
s.Close();
}
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
The problem with this function is, that it only transmits a random amount of the data, typically about one third of the byte-array of 80 bytes. I have tried different priority settings of the thread, but nothing changes.
Am I missing something important, or do I simply close the port too fast after a transmit request?
I hope you can help me. Thanks :)
No, that was a Really Bad Idea. The things that go wrong, roughly in the order you'll encounter them:
the serial port driver discards any bytes left in the transmit buffer that were not yet transmitted when you close the port. Which is what you are seeing now.
the MSDN article for SerialPort.Close() warns that you must "wait a while" before opening the port again. There's an internal worker thread that needs to shut down. The amount of time you have to wait is not specified and is variable, depending on machine load.
closing a port allows another program to grab the port and open it. Serial ports cannot be shared, your program will fail when you try to open it again.
Serial ports were simply not designed to be opened and closed on-the-fly. Only open it at the start of your program, close it when it ends. Not calling Close() at all is quite acceptable and avoids a deadlock scenario.
I think you're missing the point of the using block. A typical using block will look like this:
using (var resource = new SomeResource())
{
resource.DoSomething();
}
The opening happens at the very beginning. Typically as part of the constructor. But sometimes on the first line of the using block.
But the big red flag I see is that the closing happens automatically. You don't need the .Close() call.
If the successful operation of your serial device is dependent on the calls to Thread.Sleep then perhaps the thread is being interrupted at some point, sufficient to make the data transmission out of sync with the device. There would most likely be ways to solve this but the first thing I would do is try to use the .NET SerialPort class instead. The Write method is very similar to what you want to do, and there are C++ code examples in those articles.

Implementing stop and restart in file stream transfer - how to? C# .NET

I'm looking for texts or advice on implementing stop and restart in file stream transfer.
The goal is for the application to use a single read source, and output to multiple write sources, and be able to restart from a recorded position if a transfer fails.
The application is being written in C# .NET.
Psuedo code:
while (reader.Read())
{
foreach(writer in writers)
{
writer.WriteToStream();
}
}
I need to be able to implement stop or pause. Which could work like so. To stop, continue is marked false:
while (reader.Read() && Continue)
{
foreach(writer in writers)
{
writer.WriteToStream();
}
}
Clearly at this stage I need to record the number of bytes read, and the number of bytes written to each write source.
My questions are:
If I were to only record the read bytes, and use this for restarts, one or more writers could have written while others have not. Simply restarting using a measure of read progress might corrupt the written data. So I need to use a 'written bytes per writer' record as my new start position. How can I be sure that the bytes were written (I may not have the ability to read the file from the write source to read the file length)?
Can anyone adviser or point me in the right direction of a text on this kind of issue?
Use a thread synchronization event.
(pseudocode):
ManualResetEvent _canReadEvent = new ManualResetEvent(true);
public void WriterThreadFunc()
{
while (_canReadEvent.Wait() && reader.Read())
{
foreach(writer in writers)
{
writer.WriteToStream();
}
}
}
public void Pause()
{
_canReadEvent.Reset();
}
public void Continue()
{
_canReadEvent.Set();
}
The good thing is that the writer thread won't consume any CPU when it's paused and it will continue directly it's signaled (as opposed to using a flag and Thread.Sleep())
The other note is that any check should be the first argument in the while since reader.Read() will read from the stream otherwise (but the content will be ignored since the flag will prevent the while block from being executed).

Categories