Nonblocking io using BinaryWriter to write to usblp0 - c#

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.

Related

How to guaranteed write into file in multithreading with exceptions?

This is a simplified example
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
new Thread(() => Method1()).Start();
new Thread(() => Method2()).Start();
Console.Read();
}
private static void Method1()
{
using (StreamWriter sw = new StreamWriter(#"h:\data.txt"))
{
int i = 100000000;
while (true)
{
Thread.Sleep(100);
sw.WriteLine(i);
i++;
}
}
}
private static void Method2()
{
Thread.Sleep(6000);
throw null;
}
}
}
StreamWriter doesn't write the data into file if exception occurs too early and in another thread. File data.txt is empty at the time when exception occurs.
I played with this situation a little and found a bunch of workarounds:
If I increase the sleep interval for the exception's thread (and decrease interval between writings into file) the file will be filled with data. It is not a choice because I don't know when an exception occurs.
As a consequence of previous workaround I can decrease the buffer size of the stream writer. But it seems not working if I set it too small - for example, this code
FileStream fs = new FileStream(#"h:\data.txt", FileMode.Create);
using (StreamWriter sw = new StreamWriter(fs, Encoding.Default, 10))
doesn't work because the first writing operation occurs only when about 385 integers are waiting in the buffer to be written into file.
File will be filled if I close the writer before exception occurs. But that is not a good choice - I have to write into file from 1 to 10 times per second. It is not a good idea to open and close the writer so frequently, is it?
I can catch the exception like this
private static void Method2()
{
try
{
Thread.Sleep(6000);
throw null;
}
catch
{
Console.WriteLine("Exception!");
}
}
and all will be OK - no application termination and file will be filled pack by pack. But that is not the case also - I can't control when and where exceptions occur. I try to use try-catch everywhere but I can miss something.
So the situation is: StreamWriter's buffer is not full, exception occured in another thread and is not catched, so the application will be terminated. How not to lose this data and to write it into file?
As I understand your situation you are assuming that there is a bug somewhere and the process might be terminated at any time. You want to save as much data as possible.
You should be able to call Flush on the StreamWriter. This will push the data to the OS. If your process terminates the data will eventually be written by the OS.
In case you cannot convince StreamWriter to actually flush for some reason you can use a FileStream and write to that (pseudocode: fileStream.Write(Encoding.GetBytes(myString))). You can then flush the FileStream or use a buffer size of 1.
Of course it's best if you prevent the process from being terminated in the first place. This usually is straight forward with Task as opposed to using raw Threads.
Flushing the stream will ensure that all of it's content is pushed into it's underlying file.
That will take care of ensring all of the data is saved after you completed an operation and that a following exception will not make your application loose data.

Proper closing application with FileStream.Read

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

How to properly read line using sockets through asynchronous callback

I have a library that is connected to some network service using TCP sockets and randomly receives a data from it. I need to process these data line by line and for that I have 2 options:
Create a new thread (I don't want to do that) in which I have never ending loop which calls StreamReader.ReadLine() (I don't want to spawn new threads as this is a library and threads should be fully under control of main program)
Using async callback which gets called every time some data arrives to stream buffer. I currently use this option, but I am having troubles getting lines only. I hacked out this simple solution:
// This function reset the callback after it's processed
private void resetCallback()
{
if (this.networkStream == null)
return;
if (!string.IsNullOrEmpty(this.lineBuffer) && this.lineBuffer.EndsWith("\n"))
{
this.processOutput(this.lineBuffer);
this.lineBuffer = "";
}
AsyncCallback callback = new AsyncCallback(OnReceive);
this.networkStream.BeginRead(buffer, 0, buffer.Length, callback, this.networkStream);
}
// This function gets called every time some data arrives to buffer
private void OnReceive(IAsyncResult data)
{
if (this.networkStream == null)
return;
int bytes = this.networkStream.EndRead(data);
string text = System.Text.Encoding.UTF8.GetString(buffer, 0, bytes);
if (!text.Contains("\n"))
{
this.lineBuffer += text;
}
else
{
List<string> parts = new List<string>(text.Split('\n'));
while (parts.Count > 0)
{
this.lineBuffer += parts[0];
if (parts.Count > 1)
{
this.processOutput(this.lineBuffer + "\n");
this.lineBuffer = "";
}
parts.RemoveAt(0);
}
}
this.resetCallback();
}
As you can see I am using very nasty solution where I am basically checking in every "packet" of data that are received on buffer:
Whether data in buffer are whole line (ends with new line)
Whether data in buffer contains more than 1 line (new line is somewhere in middle of data, or there are more than 1 new line)
Data in buffer contains only a part of a line (no new line in text)
The problem here is that callback function can be called any time when some data are received, and these data can be a line, part of a line, or even multiple lines.
Based on the new line I am storing data in another buffers and when I finally get a new line, I process it somehow.
This is actually working just fine, but I am still wondering if there isn't a better solution that is more clean and doesn't require such a hacking in order to read the stream line by line without using threads?
Please note commenter Damien_The_Unbeliever's point about the issue with partial UTF8 characters. As he says, there's nothing in TCP that would guarantee that you only receive whole characters; a sequence of bytes in the stream can be interrupted at any point, including mid-character.
The usual way to address this would be to using an instance of a Decoder (which you can retrieve from the appropriate Encoding subclass, e.g. Encoding.UTF8.GetDecoder()). A decoder instance will buffer characters for you, returning only whole characters as they are available.
But in your case, there is a much easier way: use the TextReader.ReadLineAsync() method.
For example, here's an asynchronous method which will process each line of text read from the stream, with the returned task for the method completing only when the stream itself has reached the end (i.e. graceful closure of the socket):
async Task ProcessLines()
{
using (StreamReader reader = new StreamReader(
this.networkStream, Encoding.UTF8, false, 1024, true))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
this.processOutput(line);
}
}
// Clean up here. I.e. send any remaining response to remote endpoint,
// call Socket.Shutdown(SocketShutdown.Both), and then close the
// socket.
}
You would call that (preferably awaiting the result in another async method, though that would depend on the exact context of the caller) from wherever you call resetCallback() now. Given the lack of a good, minimal, complete code example a more specific explanation than that can't be provided.
The key is that, being an async method, the method will return as soon as you call ReadLineAsync() (assuming the call doesn't complete immediately), and will resume execution later once that operation completes, i.e. a complete line of text is available and can be returned.
This is the standard idiom now in C# for dealing with this kind of asynchronous operation. It allows you to write the code practically as if you are doing everything synchronously, while the compiler rewrites the code for you to actually implement it asynchronously.
(As an aside: you may want to consider using the usual .NET conventions, i.e. Pascal casing, for method names, instead of the Java-style camel-casing. That will help readers more readily understand your code examples).

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.

Using callbacks to play an audio file with port audio?

I'm trying to play a wave file with C# using the portaudiosharp bindings for the portaudio C library and am having trouble envisioning the proper way to go about doing it. I will paste the code that I am using at the moment. It works somewhat but I don't think it is the proper way of doing things.
This is my callback function:
public PortAudio.PaStreamCallbackResult myPaStreamCallback(
IntPtr input,
IntPtr output,
uint frameCount,
ref PortAudio.PaStreamCallbackTimeInfo timeInfo,
PortAudio.PaStreamCallbackFlags statusFlags,
IntPtr userData)
{
short[] mybuffer = (short[])myQ.Dequeue();
Marshal.Copy(mybuffer, 0, output, (int)frameCount * 2);
return PortAudio.PaStreamCallbackResult.paContinue;
}
And then I have a 'main loop':
PortAudio.Pa_Initialize();
IntPtr stream;
IntPtr userdata = IntPtr.Zero;
PortAudio.Pa_OpenDefaultStream(out stream, 1, 2, 8,
48000, NUM_SAMPLES/2, new PortAudio.PaStreamCallbackDelegate(myPaStreamCallback), userdata);
PortAudio.Pa_StartStream(stream);
while (readerPosition < reader.Length)
{
short[] qBuffer = new short[NUM_SAMPLES];
read = reader.Read(buffer, 0, NUM_SAMPLES * 2); //read a block out from my wave file
Buffer.BlockCopy(buffer, 0, qBuffer, 0, read); //copy them to the short buffer
myQ.Enqueue(qBuffer);
readerPosition += read;
}
while(PortAudio.Pa_IsStreamActive(stream) == 0)
{
//this while loop never gets entered -- why??
Console.WriteLine("waiting");
}
System.Threading.Thread.Sleep(5000); //need this so that the callback function fires
PortAudio.Pa_StopStream(stream);
I have tried to implement a FIFO buffer but I think I may have done it in a silly way as basically what happens is the queue gets filled up until there are no more samples left to fit in there and only then does the PA callback start firing.
What is the better way of doing this? How do I make my main loop yield so the callback function can fire without having to sleep?
I am using a NAudio wavreader to read from a wave file but I don't think that's important. I can post more details about that if it is though.
A few obvious things:
You should fill your ring buffer before calling StartStream()
You want your main loop to keep the buffer full by writing data to it whenever it isn't full. You could do this the wrong way by polling and sleeping. If the queue is big enough you can sleep for a second at a time and the overhead won't be so big.
The "right" way to do it is to use an Event object and signal it from the callback every time the queue is becomes "not full". The main() loop blocks on that Event with WFSO and wakes whenever it can write data to the queue. (hint: use an auto-reset Event).
If all you want to do is play a soundfile you could use PA's WriteStream() API which does all this internally.
Other notes:
It is non-trivial to write a correct atomic FIFO queue. You haven't shown your code for this.
Your callback doesn't deal with the case where the queue is empty. In that case it should probably output silence.
You might not want to be newing up a new buffer for every block. Consider returning used blocks to the main thread via a second queue and reusing them.
You probably want to bound the size of the queue (3-5 seconds of audio is more than enough for most scenarios) -- this is what I mean by "not full" above. Another way to think about this is in terms of a high watermark: PA callback drains the buffer while it is non-empty, main() fills the buffer while it is less full than the (e.g. 5 second duration) watermark. Callback wakes main whenever the buffer is lower than the watermark.

Categories