tags:

views:

217

answers:

3

I have a C# program that communicates with serial devices using the built in SeralPort class. However, I want to do asynchronous writes and for that I am using BaseStream.BeginWrite(). In the async callback I call BaseStream.EndWrite(). All this works fine. However, on occasion I want to close a port BEFORE the BeginWrite() has finished but calling Close() causes it to hang as long as BeginWrite() is pending. I have tried calling EndWrite() but that also hangs if BeginWrite() is pending. How do I kill the BeginWrite() thread? There appears to be no BaseStream.Abort() or similar.

Thanks

A: 

Not sure if you can: link text

n8wrl
Thanks for the link.
HiteshP
A: 

I also think that you can't cancel the operation if Stream.Close() doesn't do the trick. EndWrite() blocks by design, a sequence of BeginWrite() and EndWrite() on the same thread is identical to calling the synchronous function.

Actually, it's possible that there's not even a thread running for your operation. The operation might use IO completion ports internally and only fire the callback on a threadpool thread. (it's been some time since I looked into that stuff)

But what you can do is 'abandon' the stream, set a flag in your code and when the callback arrives, just close the stream if the flag is set. Remember to put a lock around the flag or make it volatile

chris166
I abandoned the stream and that is fine. However, attempting to reopen causes a failure. I suspect that probably it cannot be done.Interestingly, I have a commercial win32 console app that does the same thing and works fine.Thanks.
HiteshP
Have you tried writing less data in one shot? Then you can close down faster.
chris166
A: 

I have a found a way but it is a bit hackish. This method closes the port and aborts but throws a couple of exceptions in the process. Basically, I use reflection to get the device's file handle as follows:

object p = _port.BaseStream.GetType().GetField("_handle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField).GetValue(_port.BaseStream);
IntPtr hFile = (IntPtr)p.GetType().GetField("handle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField).GetValue(p);

Where *port is the opened SerialPort. I then close the file as follows

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CloseHandle(IntPtr hFile);
CloseHandle(hFile);

Probably there is a better way by calling one of the private methods in BaseStream but this is one way :)


HiteshP