.NET Forum / .NET Framework / CLR / June 2006
use SerialPort with raw device names -or- cancel pending read on FileStream
|
|
Thread rating:  |
Ben Voigt - 09 Jun 2006 17:10 GMT The SerialPort class provided by Microsoft has some code like: SerialPort.PortName set accessor if (value.StartsWith(@"\\", StringComparison.Ordinal)) { throw new ArgumentException(SR.GetString("Arg_SecurityException"), "PortName"); }
SerialStream constructor: if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException(SR.GetString("Arg_InvalidSerialPort"), "portName"); }
I have USB device names that work great with the Win32 CreateFile... but SerialPort chokes because of the arbitrary requirement imposed that serial port names look like COMn. Am I going to have to write a complete new managed serial port interface?
I tried getting a SafeFileHandle from CreateFile and SetCommState, SetCommTimeouts, and making it into a FileStream, and this works, but asynchronous reads are acting dopey. Obviously the SerialPort class does a lot of stuff specially designed for serial ports and I don't get this with FileStream. I'm worried about my pending read request, because depending on the timeouts specified sometimes I get a CancelledOperationException when I close the serial port, but sometimes the operation stays pending... no callback, no signalled event.
"Jeffrey Tan[MSFT]" - 12 Jun 2006 06:51 GMT Hi Ben,
Thanks for your post!
Yes, Serial Port in Windows requires the port name to start with "COM". The .Net2.0 SerialPort is not designed to work with USB device, it is used for serial port. Based on my experience, there is no build-in support for USB device in .Net currently. I think you still have to p/invoke CreateFile Win32 API to open the USB device for manipulation. Actually, SerialPort class internally also encapsulates CreateFile.
Regarding your second question, I did not understand completely. Can you provide some more background information? How do you do asynchronous read operation in .Net?
Thanks!
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Barry Kelly - 12 Jun 2006 08:41 GMT > Regarding your second question, I did not understand completely. Can you > provide some more background information? How do you do asynchronous read > operation in .Net? Ben said:
> I tried getting a SafeFileHandle from CreateFile and SetCommState, > SetCommTimeouts, and making it into a FileStream, and this works, but > asynchronous reads are acting dopey. It would thus appear that he is using Stream.BeginRead().
-- Barry
 Signature http://barrkel.blogspot.com/
Ben Voigt - 12 Jun 2006 14:57 GMT >> Regarding your second question, I did not understand completely. Can you >> provide some more background information? How do you do asynchronous read [quoted text clipped - 7 lines] > > It would thus appear that he is using Stream.BeginRead(). That's correct. After setting EFileAttributes.Write_Through | EFileAttributes.Overlapped in the CreateFile call, things are working more smoothly. There are still a lot of things done behind the scenes in SerialPort, like time-sensitive instead of throughput-optimized buffering, that I'll be having to figure out.
Basically, what I was seeing without EFileAttributes.Overlapped set was that at stream close, the BeginRead would sometimes complete, invoking the callback which threw a OperationCanceledException from EndRead, and sometimes continue on. This prevented me from Disposing the stream, because the callback was sometimes still called much later.
With the Overlapped flag set, it seems that the callback is never called and the IAsyncResult's event is not signalled. I'm still trying to decide whether I could have trouble if I close the stream while the callback is executing on a worker thread...
I'm now thinking that I might need to ditch FileStream as well and do everything directly with the Win32 API (I'll use C++/CLI instead of pinvoke if I go this route) so I can use (for example) CancelIo.
Can someone explain to me how asynchronous I/O and thread pools interact? Is it true that a thread pool is only used if the handle is associated to a completion port, and that otherwise the callback is done as an APC in the thread that issued the ReadFileEx request? Does the .NET Framework use alertable waits (it seems no, PeekMessage and GetMessage instead of MsgWaitForYYYEx)? An special considerations I should be aware of if I replace Application.Run with my own MsgWaitForYYYEx loop (like modal dialogs still using the framework message loop, etc.)? I've done this with native C++ before but not in a managed application.
I'm strongly considering keeping this application single-threaded and working on re-entrancy instead of thread safety... it is targeted at an embedded device so I won't have HyperThreading/multi-cores to drive a need for additional threads.
> -- Barry "Jeffrey Tan[MSFT]" - 13 Jun 2006 07:46 GMT Hi Ben,
Thanks for your feedback!
Based on my knowledge, doing asynchronized I/O operation requires opening the device with FILE_FLAG_OVERLAPPED flag. This is stated in CreateFile MSDN documentation: "If this flag is not specified, then I/O operations are serialized, even if the calls to the read and write functions specify an OVERLAPPED structure."
>Can someone explain to me how asynchronous I/O and thread pools interact? Currently, this type of internal design information is not public documented yet. However, you can still use Reflector to view the FCL source, so you can explore it youself. Based on my basic research, FileStream.BeginRead method internally encapsulate with ReadFile Win32 API instead of ReadFileEx. So FileStread.BeginRead does not use alertable I/O for asynchronized I/O operation.
Since .Net FCL does not p/invoke CreateIoCompletionPort API internally, .Net does not use I/O completion port for asynchronized I/O operation either.
If you really want to design high performance and scalable application in .Net, you may p/invoke CreateIoCompletionPort to implement ICOP yourself, please refer to the article below for some guide: "IOCP Thread Pooling in C#" http://www.devarticles.com/c/a/C-Sharp/IOCP-Thread-Pooling-in-C-sharp-Part-I /
Finally, the sample below provided a sample implementation of asnychronous SerialStream: "SerialStream - use the serial port as a Stream" http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=fcba7 fc5-666e-4eb0-863f-0045b0c79ec7
Hope this helps!
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 13 Jun 2006 23:29 GMT > Hi Ben, > [quoted text clipped - 16 lines] > FileStread.BeginRead does not use alertable I/O for asynchronized I/O > operation. Yes, I've been looking, mostly at Windows.Forms.Application+ThreadContext which is the main loop, which has no support for APCs. Wondering if maybe there was a really good reason for that.
At any rate, it doesn't look like I'd be able to set up an alertable message loop on the main thread because the first modal dialog called up from any component is going to stall the main message loop. But there's this MessageLoopCallback delegate which is public but miniscule documentation... more hours with Reflector in my future.
> Since .Net FCL does not p/invoke CreateIoCompletionPort API internally, > Net does not use I/O completion port for asynchronized I/O operation [quoted text clipped - 24 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. "Jeffrey Tan[MSFT]" - 14 Jun 2006 06:32 GMT Hi Ben,
Thanks for your feedback!
MsgWaitForMultipleObjectsEx is used to place the calling thread in alertable state where this thread contains message loop(create windows). Yes, .Net Winform main GUI thread did not build this feature in its message loop. Is there any special reason that you have to queue APC to the main GUI thread? I think you'd better use other non-GUI thread for APC callback. In non-GUI thread, other APIs can be used to jump into alertable state: SleepEx, SignalObjectAndWait, WaitForMultipleObjectsEx, or WaitForSingleObjectEx function etc..
.Net System.Threading.ThreadPool class can be used to manage thread pooling and asychronous I/O operations. You might want to give it a try. For more information, please refer to the 2 articles below: "Programming the Thread Pool in the .NET Framework" http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/ht ml/progthrepool.asp "The CLR's Thread Pool" http://msdn.microsoft.com/msdnmag/issues/03/06/NET/
Hope this helps!
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 14 Jun 2006 15:52 GMT > Hi Ben, > [quoted text clipped - 7 lines] > GUI thread? I think you'd better use other non-GUI thread for APC > callback. Because I want only one other thread -- to run a watchdog timer. If I have multiple threads, then (1) my objects can no longer trigger events to GUI components, (2) all objects need to become thread-safe, and (3) I need a whole host of watchdogs.
I'm not worried about keeping the GUI responsive while stuff happens in the background, if anything in the system hangs, the user had best be able to tell -- this will be a medical device running XP embedded. Deployment will include some nasty physical conditions, so failures will happen, and the last thing I want are silent failures.
What I am wanting is asynchronous notification of arriving data. Sockets have WSAAsyncSelect (which, using messages, will work with Application+ThreadContext's PeekMessage/GetMessage loop), timers can send messages too. I'm looking for something equivalent for serial port i/o. I thought APCs would be the trick. Do you know of something better? Maybe if I keep the extra threads to I/O only, I can keep the processing single-threaded. I'll just use a thread-safe linked list for data transfer, and post a windows message when activity occurs.
I had good luck in unmanaged C++ with acquiring some data, then passing a pointer to the buffer to PostMessage for processing and display... but I suspect this will wreak havoc with the CLR and result in my buffers being garbage collected during transit... back to the standard heap then.
Does InterlockedCompareExchange work with gc handles?
> In non-GUI thread, other APIs can be used to jump into alertable state: > SleepEx, SignalObjectAndWait, WaitForMultipleObjectsEx, or > WaitForSingleObjectEx function etc.. > > Net System.Threading.ThreadPool class can be used to manage thread pooling > and asychronous I/O operations. You might want to give it a try. For more ... but I'm not looking for throughput.
> information, please refer to the 2 articles below: > "Programming the Thread Pool in the .NET Framework" [quoted text clipped - 14 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. Barry Kelly - 14 Jun 2006 16:32 GMT > Because I want only one other thread -- to run a watchdog timer. If I have > multiple threads, then (1) my objects can no longer trigger events to GUI > components, [...]
> I'll just use a thread-safe linked list for data transfer, > and post a windows message when activity occurs. Sorry for butting in, but: the idiom in .NET for communicating with the GUI thread from a background thread is to use Control.Invoke or ISynchronizeInvoke.Invoke (all controls implement ISynchronizeInvoke) e.g. in C# 2.0:
control.Invoke((EventHandler) delegate { control.TriggerEtc(); });
-- Barry
 Signature http://barrkel.blogspot.com/
Ben Voigt - 14 Jun 2006 21:46 GMT >> Because I want only one other thread -- to run a watchdog timer. If I >> have [quoted text clipped - 10 lines] > > control.Invoke((EventHandler) delegate { control.TriggerEtc(); }); I'm aware of this, it appears to be a blocking cross-thread call, like DCOM calls into an STA or SendMessage. It appears that Control.Invoke uses PostMessage followed by ManualResetEvent.WaitOne. This makes it both slow and prone to deadlock. It breaks deadlocks by enforcing a 1000ms timeout that the documentation does not mention.
> -- Barry Barry Kelly - 15 Jun 2006 06:51 GMT > > control.Invoke((EventHandler) delegate { control.TriggerEtc(); }); > [quoted text clipped - 3 lines] > and prone to deadlock. It breaks deadlocks by enforcing a 1000ms timeout > that the documentation does not mention. Yes, it is synchronous. There's always BeginInvoke, of course.
-- Barry
 Signature http://barrkel.blogspot.com/
"Jeffrey Tan[MSFT]" - 15 Jun 2006 08:08 GMT Hi Ben,
Thanks for your feedback!
> (3) I need a whole host of watchdogs. What do you mean by this point?
> I'm not worried about keeping the GUI responsive while stuff happens in the > background, if anything in the system hangs, the user had best be able to > tell It seems that you are not worried about hanging in GUI thread. Unfortunately, currently, .Net winform GUI thread does not include MsgWaitForMultipleObjectsEx API, so we can not queue APC on main GUI thread.
Doesn't FileStream.BeginWrite method meet your need? What problem do you meet while using it? You'd better give a read to the "Asynchronous I/O Operations" section in the article I provide in the original reply.
Regarding the p/invoke memory issue, I am not familiar with it. Based on my experience, if you allocate the buffer with Marshal.AllocCoTaskMem to alloc the memory, it will not be GCed during usage.
Thanks.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 15 Jun 2006 16:17 GMT > Hi Ben, > > Thanks for your feedback! > >> (3) I need a whole host of watchdogs. > What do you mean by this point? Every thread needs to have a watchdog, which is basically just an integer variable. Every thread will periodically load its watchdog with some value, say 10, from either a timer message or other main processing loop. An independent high-priority thread wakes periodically, calls InterlockedDecrement on each watchdog. Any watchdog that reaches zero indicates a thread stuck performing a subtask, due to deadlock, or synchronous I/O on a broken network connection, or logic that allowed an infinite loop for some particular input data, or whatever other reasons cause programs to hang.
>> I'm not worried about keeping the GUI responsive while stuff happens in > the [quoted text clipped - 8 lines] > meet while using it? You'd better give a read to the "Asynchronous I/O > Operations" section in the article I provide in the original reply. It's not writing, that can be synchronous since I won't be sending large amounts of data. I can use BeginRead, with the callback, but I believe the callback takes place from the threadpool? Which leaves me with the same synchronization issues. Also, I see no way to cancel a BeginRead call. With direct WinAPI calls, there's CancelIO.
> Regarding the p/invoke memory issue, I am not familiar with it. Based on > my > experience, if you allocate the buffer with Marshal.AllocCoTaskMem to > alloc > the memory, it will not be GCed during usage. The only issue is my lack of expertise concerning p/invoke. I know C++ so I've only used IJW.
> Thanks. Thanks for all your patient help.
> Best regards, > Jeffrey Tan [quoted text clipped - 5 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. "Jeffrey Tan[MSFT]" - 16 Jun 2006 03:54 GMT Hi Ben,
Thanks for your feedback!
Oh, I think I understand your requirement much better now. It seems what you want to achieve is placing the pure I/O operation in the background thread pool thread, while get the result callback in the main GUI thread, not from a worker thread.
Yes, based on my debugging, I found that the .Net CLR internal mechanism invokes the BeginWrite/Read callback routine in another thread pool thread, not the main GUI thread. Below is the callback stack I got with managed symbol debugging:
0372f9d8 010a0317 [DEFAULT] [hasThis] Void AsynchronousTest.Form1.EndWriteCallback(Class System.IAsyncResult) at [+0x17] [+0xa] g:\program\winform\2006\6-16\asynchronoustest\form1.cs:92 0372fad8 7923c069 [FRAME: GCFrame] 0372fbd0 7923c069 [FRAME: ECallMethodFrame] [DEFAULT] [hasThis] Object System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(Cla ss System.Reflection.MethodBase,SZArray Object,Object,I4,Boolean,ByRef SZArray Object) 0372fbf4 79af513e [DEFAULT] [hasThis] Class System.Runtime.Remoting.Messaging.IMessageCtrl System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(Class System.Runtime.Remoting.Messaging.IMessage,Class System.Runtime.Remoting.Messaging.IMessageSink) 0372fc5c 79aea95f [DEFAULT] Void System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Obje ct)
Note: the top stack frame is the callback routine I defined in my application.
Based on my research, the current .Net implementation does not embed the function of callback to GUI thread, so if you want to achieve this, you have to p/invoke the APC message loop yourself. However, because of the complexibility of .Net winform message loop, there is no easy way of reinventing the wheel yourself. Also, I am not if there is any potential problem regarding interoperation between your implementation of message loop and .Net Form/Control classes. I think the simplest workaround is changing your code to be thread-safe and allowing multithreading in your main application, or you may have to use synchronous I/O.
.Net FileStream class does not support CancelIO function, you have to p/invoke CancelIO API to get this done. Please refer to the articles below for a sample: "Use P/Invoke to Develop a .NET Base Class Library for Serial Device Communications" http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/ "Serial Communications : The .NET Way" http://www.codeproject.com/dotnet/DotNetComPorts.asp
P/invoke related issues can be got most professional help in the microsoft.public.dotnet.framework.interop newsgroup. Anyway, the 2 articles below both demonstrate the usage of p/invoke, which may give you a good sample.
I know that there are many aspects you have concern regarding .Net CLR/FCL, if you feel it a uncomfortable, I recommend you feedback these concern in the MSDN Product Feedback Center below: http://connect.microsoft.com/Main/content/content.aspx?ContentID=2220
Thanks for your understanding and patient.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 16 Jun 2006 20:04 GMT > Hi Ben, > [quoted text clipped - 4 lines] > thread pool thread, while get the result callback in the main GUI thread, > not from a worker thread. Yes, exactly (minus the words thread pool).
> Yes, based on my debugging, I found that the .Net CLR internal mechanism > invokes the BeginWrite/Read callback routine in another thread pool [quoted text clipped - 32 lines] > changing your code to be thread-safe and allowing multithreading in your > main application, or you may have to use synchronous I/O. I've been writing a C++/CLI library. The event-driven interface I'm exposing lends itself rather well to a message-passing architecture. I've got a threadsafe queue used to pass requests to the worker thread (custom ThreadProc, sits and calls WaitForSingleObjectEx). An event is set each time an item is added to the queue, thus waking the worker thread. Responses are posted to a windows message queue in the GUI thread (my managed class derives from NativeWindow to catch these and will be firing events within the next couple hours).
The managed class calls CreateFile to open the port, then GetCommState and GetCommTimeouts to initialize its internal data structures, then places the handle in a request. The handle will never be used from the GUI thread again. The objects passed using the request queue and message queue are reference counted.
The only shared variables are the threadsafe queue and reference counts, which all use the Interlocked family of functions. There is no contention possible, although InterlockedCompareExchangePointer could fail on a multiprocessor system and have to retry. Other than the InterlockedCompareExchangePointer loop, the GUI thread performs no waits whatsoever.
I will be able to use this same worker thread for all serial port connections (up to a dozen on this product collecting data from different medical devices, plus internal system status), and I can also handle other notifications as well:
By adjusting the timeout parameter to WaitForSingleObjectEx, I can implement a large number of timers. By using WaitForMultipleObjectsEx, I can add socket I/O with WSAEventSelect.
> Net FileStream class does not support CancelIO function, you have to > p/invoke CancelIO API to get this done. Please refer to the articles below Additional caveat: p/invoke CancelIo can't be combined with BeginRead/EndRead, since they execute on a thread pool thread, and CancelIo must be called from the thread issuing the ReadFile(Ex) call. This situation will improve somewhat with CancelIoEx in Vista. I will submit some feedback that the SerialPortAsyncResult should provide a managed interface to the CancelIoEx function for Vista, because otherwise the LPOVERLAPPED structure identifying the operation is not available to consumers.
> for a sample: > "Use P/Invoke to Develop a .NET Base Class Library for Serial Device [quoted text clipped - 26 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. Ben Voigt - 16 Jun 2006 20:28 GMT >> Hi Ben, >> [quoted text clipped - 87 lines] > the LPOVERLAPPED structure identifying the operation is not available to > consumers. Posted here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID= 137076 and here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID= 137088
>> for a sample: >> "Use P/Invoke to Develop a .NET Base Class Library for Serial Device [quoted text clipped - 26 lines] >> This posting is provided "AS IS" with no warranties, and confers no >> rights. "Jeffrey Tan[MSFT]" - 19 Jun 2006 09:50 GMT Hi Ben,
Thanks for your feedback!
I am glad you finally got a workaround regarding this issue.
Regarding your 2 feedback requests, I still have some comment:
1, "P/Invoke CancelIo will not work, because the CancelIo call must be made from the thread which requested the operation, but the implementation makes the call from the thread pool."
Yes, CancelIo API will only cancel all the pending input and output (I/O) operations that are issued by the calling thread for a specified file handle. Can you tell me what leads you to believe that it is the ThreadPool thread who makes the call to the I/O when using BeginRead? Based on my research with Reflector, the call stack to ReadFile win32 API looks like this:
Win32Native.ReadFile(which p/invokes to Kernel32!ReadFile) FileStream.ReadFileNative FileStream.BeginReadCore FileStream.BeginRead
So it seems that the thread calling FileStream.BeginRead is the thread who issues the I/O read operation. You can use the CancelIo in the same thread as FileStream.BeginRead to cancel the I/O operations. If I have misunderstood you, please feel free to tell me, thanks.
2. "Because Windows Forms uses PeekMessage/GetMessage, functions requiring alertable waits such as waitable timers and ReadFileEx/WriteFileEx cannot be used from a GUI thread."
Yes, just as we previous discussed, winform message loop does not encapulate the alertable I/O waiting with MsgWaitForMultipleObjectsEx. Also, FileStream.BeginRead calls back the callback_proc in the ThreadPool thread. However, in your scenario, your callback_proc needs to execute the post-I/O processing in the GUI thread because of the non-thread safe watch dog. I think this is your key problem.
Is it possible for you to use Control.BeginInvoke method in the Thread Pool callback_proc to queue an asynchronous work to the GUI thread? With this way, you can forward the callback work to the GUI thread and will eliminate the thread safe issue.
Hope this helps!
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 19 Jun 2006 16:13 GMT > Hi Ben, > [quoted text clipped - 25 lines] > as FileStream.BeginRead to cancel the I/O operations. If I have > misunderstood you, please feel free to tell me, thanks. Ok. I may have gotten confused between the paths for asynchronous (BeginRead/EndRead) I/O with files opened with/without the overlapped flag.
> 2. "Because Windows Forms uses PeekMessage/GetMessage, functions requiring > alertable waits such as waitable timers and ReadFileEx/WriteFileEx cannot [quoted text clipped - 6 lines] > post-I/O processing in the GUI thread because of the non-thread safe watch > dog. I think this is your key problem. Well, actually the watchdog will the threadsafe, but it will only watch particular threads. Tell me, what happens if the application gets into a state causing the threadpool callbacks to stall (either a resource deadlock, or walking a singly-linked list that got crossed back on itself, etc)? My assumption is that the OS would create a new thread for each callback until the threadpool limit is reached, and then callbacks would stop, the app would allocate additional resources for each new I/O request which could never be freed. The main application may timeout on the data, but it will be difficult to distinguish from an unresponsive (powered off, disconnected) serial device. This seems to be a serious drawback of the threadpool.
I intend to ship an app where this isn't possible, but at least during development, being able to reliably detect this condition will be very helpful. My team is doing software and hardware design for the processor subsystem as well and hardware and firmware for many of the devices... and in my experience, when problems occur, they may be very difficult to reproduce, or may only appear after the system runs for some time, causing an integer overflow or such. Knowing where the failure lies is a big step toward fixing it.
As I am implementing a single worker thread for my I/O, I can specify a timeout in the WaitForSingleObjectEx call, and reset the watchdog each time through the loop. Thus if the watchdog timer runs out, I can start some recovery action (probably halt all other threads, dump data to disk as necessary, write a minidump, and restart the process). If I was using threadpool, managing watchdogs would be a very tricky operation (probably requiring synchronized access to some list of running threads, which adds the potential to involve the watchdog thread in a deadlock).
> Is it possible for you to use Control.BeginInvoke method in the Thread > Pool > callback_proc to queue an asynchronous work to the GUI thread? With this > way, you can forward the callback work to the GUI thread and will > eliminate > the thread safe issue. This probably works quite well under nominal conditions.
> Hope this helps! You've been very helpful. Thanks for taking the time to understand my problem space.
> Best regards, > Jeffrey Tan [quoted text clipped - 5 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. "Jeffrey Tan[MSFT]" - 20 Jun 2006 04:28 GMT Hi Ben,
You are welcome.
Yes, FileStream.BeginWrite/Read queues the asynchronous I/O to OS, then .Net ThreadPool thread will execute your provided callback procedure.
Note: .Net ThreadPool manages a pool of spawned threads which are live with ThreadPool, so whenever the callback is executing, .Net will not create a new thread, it just reuses one of the ThreadPool live thread to execute the callback procedure. If your callback procedure blocks in the execution, threadPool can not reuse the first ThreadPool thread, and it has to use another live thread in the pool to execute the second callback procedure. So if all the callback procedure blocks in the execution, your application callback may use out of the ThreadPool threads.
As we can see in "ThreadPool.GetAvailableThreads" method in MSDN: "If there are no available threads, additional thread pool requests remain queued until thread pool threads become available."
So if you used out of the ThreadPool threads, there maybe a great performance issue in your application threading model, especially when you are queuing a lot of asynchronous I/O requests. You'd better not block too long in callback procedure.
>Knowing where the failure lies is a big step toward fixing it You can use ThreadPool.GetAvailableThreads method to determine the free thread in ThreadPool. This method may give you some hint whether the unresponsive is caused by bad serial device or pooling issue.
If you really have to block in the ThreadPool callback, you have 2 workarounds: 1. Spawn a new thread to execute the reminding work and exit the callback. 2. Queue an asynchronous request to the GUI thread with Control.BeginInvoke. By doing this, the callback work has been forwarded to the GUI thread in MessageLoop. Note: if you are doing this, the GUI thread may have a lot of work to do, and it may hang in the work, which gives a non-responsible UI to the customer.
Thanks.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 20 Jun 2006 15:43 GMT > Hi Ben, > [quoted text clipped - 30 lines] > If you really have to block in the ThreadPool callback, you have 2 > workarounds: Thanks. Looks like ThreadPool.GetAvailableThreads would have provided some of the information I was looking for. But, I'm already done implementing the single worker-thread version, so I don't think I'll be trying to use the ThreadPool. My concerns about callbacks blocking aren't from a design perspective, but rather an attitude of "bugs happen, especially during development" and a desire to be able to find out exactly what's going on. Also, I work on medical systems for NASA, and sooner or later our device will take a radiation hit. When that happens, I want to maximize the chance of detecting it and, in case of a soft hit, recover.
Basically radiation causes the same set of problems as an unstable power supply, but affects CPU and memory more than I/O buses: * soft hit = data corruption (knocked some electrons around, changing the capacitive charge in a DRAM cell or CPU register) * hard hit = permanent physical damage (ionization created a conducting path, allowing a large current to flow and breaking down a capacitive structure, like a FET) * severely reduced product life
These effects only happen when the device is powered up (soft hits are corrected during bootup, hard hits require current from the power supply), and there's spare equipment, so the worst thing is a silent failure.
> 1. Spawn a new thread to execute the reminding work and exit the callback. > 2. Queue an asynchronous request to the GUI thread with [quoted text clipped - 15 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. "Jeffrey Tan[MSFT]" - 22 Jun 2006 04:48 GMT Hi Scott,
Oh, I was not aware that there are so much background information in your design. Yes, you may live with your current single worker-thread design.
:-) Additionally, regarding your original SerialPort port name starts with "\\.\" issue, I have helped you to forward it to the developer team, below is the feedback: "True but we do not allow you to use ¡°\\.\¡± device names anywhere else in the framework. You can¡¯t even use these names with FileStream even though you could call CreateFile.
This is done to reduce the risk and the attack surface area associated with SerialPort and at the time we did not have any information that was an important scenario. Though we have gotten feedback like your from at least one other customer and we are considering supporting this in a future release."
Currently, I think you have to p/invoke CreateFile to workaround this issue.
Hope my effect makes sense to you.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
"Jeffrey Tan[MSFT]" - 15 Jun 2006 08:14 GMT If I am not clear in my reply, I mean that you may use FileStream.BeginWrite method to start the asynchronized I/O operation in GUI thread and get the callback result in UserCallback method. Does it meet your need? Please feel free to feedback your concern regarding it. Thanks.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 12 Jun 2006 15:08 GMT > Hi Ben, > [quoted text clipped - 4 lines] > Net2.0 SerialPort is not designed to work with USB device, it is used for > serial port. I guess I need to clarify: The device is a serial port. It implements the serial port device interface GUID_DEVINTERFACE_COMPORT and appears in the ports listing of the Device Manager. It does not matter to Windows whether the serial port is connected via a PCI bus or USB bus, whether it is found by the ACPI or USB plug-and-play enumerator. The device even receives a "COMn" alias. But "COMn" is not given to me by RegisterDeviceNotification, the plug-and-play name is. The "COMn" mapping can change as devices are plugged and unplugged, and by reboots. If I start hunting around in the registry for the mapping, I will have a race condition. I want to use only the PnP device name that comes with RegisterDeviceNotification because it has the device serial number embedded and I therefore know what device is connected.
> Based on my experience, there is no build-in support for USB device in > .Net [quoted text clipped - 18 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. "Jeffrey Tan[MSFT]" - 13 Jun 2006 07:12 GMT Hi Ben,
Thanks for your feedback!
Sorry, I do not have much experience on native device related serial port design. If your device has implemented the serial port device interface and its name is not started with "COM", I think you have to p/invoke Win32 APIs to do the I/O operations. Anyway I will try to perform an internal consulting regarding why SerialPort requires port name with "COM". I will feedback any further findings here.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
"Jeffrey Tan[MSFT]" - 14 Jun 2006 04:20 GMT Hi Scott,
Sorry for letting you wait.
Below is our FCL team's feedback:
We require the port name to start with COM because we call CreateFile by appending the port name ¡°\\.\¡± and we did not want to allow the user to pass in strings like ¡°PHYSICALDRIVE0¡± and do bad things with devices like this.
I am not sure that this will work with your specific device but the mapping between device names and com ports is in the registry at: HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM. You might be able to enumerate these entries to find the COM port number that goes with your device.
Hope this makes sense.
Best regards, Jeffrey Tan Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Ben Voigt - 14 Jun 2006 21:34 GMT > Hi Scott, > [quoted text clipped - 7 lines] > like > this. I think the correct behavior would be to prepend \\.\ only if the portname starts with "COM", and use all other names as presented. It's not the responsibility of the FCL to determine what is "too dangerous"; once you start down that track you might as well not sell compilers or run any code not written by Microsoft..... oops, I guess that's what the Intel Secure Computing initiatives are. Will we next see FileStream weighed down with a bunch of code checking that you don't open "%SYSTEMDRIVE%\boot.ini" in write mode, or "%SYSTEMROOT%\System32\Config\*" where the machine registry hives are stored? CreateFile doesn't perform any of these checks, it just enforces access control and file locking. If \\.\PHYSICALDRIVE0 has an ACL giving me access, the FCL should let me open it.
For those people who pass around tainted data without checking it, and run with the SYSTEM account, there could be a SafeOpen that restricts the parameters and DeviceOpen that uses the parameter exactly as passed. Really though, much better to put the effort into doing a perl-style taint check and generating compile-time errors for unvalidated user inputs, ala how FxCop checks that public methods test for null arguments.
> I am not sure that this will work with your specific device but the > mapping > between device names and com ports is in the registry at: > HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM. You might be able to > enumerate these entries to find the COM port number that goes with your > device. The entries there have the form \Device\VCP128 What I get from RegisterDeviceNotification (via WM_DEVICECHANGE) looks like: \\?\ftdibus#vid_0403+pid_6010+75ouhtg7aa#0000#{86e0d1e0-8089-11d0-9ce4-08003e301f73} The port number is stored under HKLM\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_0403+PID_6010+75OUHTG7AA\0000\DeviceParameters\PortName, but that path is not accessible through SetupDiOpenDeviceInterfaceRegKey or SetupDiGetDeviceRegistryProperty and is probably manufacturer-specific.
> Hope this makes sense. > [quoted text clipped - 7 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|