Ok so lets say all I have is the reference of a System.Threading.Thread called thread A and I'm on another thread, lets say thread B. Now I need to execute a bit of code on thread A for a moment, then switch back. Using the reference I have, how can I Invoke thread A to do an action in it?
Well I'm making a c++/cli library. One of my objects has a thread affinity. I enter a method, I need to swap threads like you would in a Dispatcher.Invoke.
void AllegroSharp::Display::DrawToBackBuffer(BitmapImage^ image)
{
al_draw_bitmap(image->GetBitmap(), (float)image->Rect->Position->X, (float)image->Rect->Position->Y, 0);
}
DrawToBackBuffer gets called on thread B and al_draw_bitmap needs to be called on Thread A, which I have a reference to. How can I do this on thread A? Thread B is just some thread that c# spawned when I did a Task.Run in managed code.
Threads run one set of instructions from start to finish. If thread A is already running, it will execute whatever code it's been told to run from start to finish. You won't be able to change what it's running unless it is actively monitoring some shared memory for instructions on what to do next. Typically the way you implement this is by having a thread run in a loop and, inside that loop, check a message queue. Then have other threads add messages to that queue to give the looping thread work to do. There are a lot more details to make it work right, but that's the basic idea.
If, in your particular scenario, thread A is the application's GUI thread, this message passing mechanism is already set up for you, and you can use Control.Invoke (winforms) or Dispatcher.Invoke (WPF) to pass a unit of work to the GUI thread and wait for it to be completed.
Edit: this answer has been rendered less applicable by the addition of new information to the question. Ah well.
I'm building a VSTO add-in: I need to run a background thread, but this thread needs to access COM components (I've implemented IMessageFilter to make this messaging as safe as possible). All threads which access OLE or COM have to be STA I believe; thus, BackgroundWorker is off the table.
I am happy to use the normal thread and set the ApartmentState to STA, but I also need to know when this thread as finished so I can update some UI stuff. I do not want to Join() because it will lock the UI (which is the whole reason I'm using threads!).
Is the best practice to trigger some kind of event at the end of my threaded method, and have the event do the onfinished stuff I need?
OR
Is it better to poll
while(!_threadFinishedStarting)
{
Application.DoEvents();
Thread.Sleep(100);
}
As mentioned here: C#.net - How to alert program that the thread is finished (event driven)?
Thanks so much
You can call Thread.SetApartmentState() to select an STA before you start the thread. You must also pump a message loop, a requirement for STA threads. That tends to be difficult and is often skipped, you know you need one if your code deadlocks or your IMessageFilter complains.
Beware of the other requirement, an STA is only efficient when you also create the object you want to use on that same thread. That tends to be a problem in a VSTO add-in, you normally want to use an object provided by the Office object model. You don't get to choose where that object was created.
If that's accurate at all then you are not ahead with creating your own STA thread since the calls get marshaled anyway. In which case a BGW is just fine since you can't get ahead anyway, the call gets marshaled in both cases. There is no free lunch for thread-safety.
I'm building a WPF app which will do some heavy work in the background. The issue is that when I run the task in the unit tests, it usually takes about 6~7s to run. But when I run it using TPL in WPF app, it takes somewhere between 12s~30s to run. Is there a way to speed up this thing. I'm calling COM api of LogParser to do the real work.
Update:
My code for calling Log Parser API looks like below
var thread = new Thread(() =>
{
var logQuery = new LogQueryClassClass();
var inputFormat = new COMEventLogInputContextClassClass
{
direction = "FW",
fullText = true,
resolveSIDs = false,
formatMessage = true,
formatMsg = true,
msgErrorMode = "MSG",
fullEventCode = false,
stringsSep = "|",
iCheckpoint = string.Empty,
binaryFormat = "HEX"
};
try
{
Debug.AutoFlush = true;
var watch = Stopwatch.StartNew();
var recordset = logQuery.Execute(query, inputFormat);
watch.Stop();
watch = Stopwatch.StartNew();
while (!recordset.atEnd())
{
var record = recordset.getRecord();
recordProcessor(record);
recordset.moveNext();
}
recordset.close();
watch.Stop();
}
catch
{
}
finally
{
if (logQuery != null)
{
Marshal.ReleaseComObject(logQuery);
GC.SuppressFinalize(logQuery);
logQuery = null;
}
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
The thing now is with this change, I can see about 3 - 4s improvement in debugging mode, but not when I hit Ctrl + F5 to run it which is quite beyond me. How come??
The problem here is that the COM object you're using will only run on an STA thread. Several people already suggested this, but I decided to check, just to be sure. I installed the LogParser SDK, and here's what it puts in the registry for the CLSID associated with the MSUtil.LogQuery ProgID:
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{8CFEBA94-3FC2-45CA-B9A5-9EDACF704F66}]
#="LogQuery"
"AppID"="{3040E2D1-C692-4081-91BB-75F08FEE0EF6}"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{8CFEBA94-3FC2-45CA-B9A5-9EDACF704F66}\InprocServer32]
#="C:\\Program Files (x86)\\Log Parser 2.2\\LogParser.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{8CFEBA94-3FC2-45CA-B9A5-9EDACF704F66}\ProgID]
#="MSUtil.LogQuery.1"
[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{8CFEBA94-3FC2-45CA-B9A5-9EDACF704F66}\VersionIndependentProgID]
#="MSUtil.LogQuery"
It's that "ThreadingModel"="Apartment" that's the clincher. This COM class is declaring that it can only run on an STA thread.
Both the TPL and the BackgroundWorker use MTA threads. The consequence of this is that when you use the LogParser from either a TPL task or a BackgroundWorker the COM runtime detects that you're on the wrong kind of thread, and will either find or create an STA to host the object. (In this particular case it'll use what's called the 'host STA', a thread that COM creates specially for this purpose. There are some scenarios in which it'll use your main UI thread instead, but that's not the case here.)
COM then automatically marshals any calls from your worker thread over to that STA thread. It does this via a Windows message queue, so for each method you execute (and remember, property accessors are just methods in disguise, so this applies to property use too), your worker thread will send a message to that STA thread, that STA thread's message pump then has to pick that message up and dispatch it, at which point the COM runtime will call the method on the LogParser for you.
This is slow if you've got an API that involves a high volume of calls.
This is neither a WPF nor a Windows Forms issue by the way. It is entirely to do with using an STA-based COM object from a non-STA thread. You could reproduce exactly the same problem with a console app too, if you were using a non-STA thread in that. And the problem isn't specific to either the TPL or the BackgroundWorker - it will afflict anything that uses the thread pool, because thread pool threads all use MTA, not STA.
The solution is to use an STA thread. And the best way to do that is create a dedicated thread. Use the Thread class in the System.Threading namespace to launch your own thread. Call its SetApartmentState method before starting it. Make sure that the code that creates instances of objects from the LogParser API is running on that thread, and also make sure that you only ever use those objects from that thread. This should fix your performance issues.
Edited 21st Feb 2013 to clarify:
Note that it's not simply enough to ensure that you are using the COM object from an STA thread. You must use if from the same STA thread on which you created it. Basically, the whole reason for having the STA model is to enable COM components to use a single-threaded model. It enables them to assume that everything that happens to them happens on one thread. If you write multi-threaded .NET code that uses an STA thread from multiple threads, it will, under the covers, ensure that the COM object gets what it wants, meaning that all access will go through the thread it belongs to.
This means that if you call it from some other thread than its home STA thread, then even if that other thread also happens to be an STA thread, you'll still be paying the cross-thread price.
Edited 25th Feb 2013 to add:
(Not sure if this is relevant to this particular question, but could well be of interest to other people landing on this question through a search.) A downside of moving work onto a separate worker thread is that if you want to update the UI in any way as a result of processing these records, you're now on the wrong thread. If you're using databinding an INotifyPropertyChanged, WPF will automatically handle the cross-thread change notification for you, but this can have significant performance implications. If you need to do a lot of work on a background thread, but that work needs to end up updating the UI, you may need to take steps to batch those updates. It's not completely trivial - see the series of blog entries starting here: http://www.interact-sw.co.uk/iangblog/2013/02/14/wpf-async-too-fast
COM uses message queues for IPC. I'm unclear what determines which message queue, but I suspect it's the shell message queue because the Delphi debugger and Outlook used to play merry hell with each other. My unproven hypothesis is that an out of process COM server can be stalled by something else stallings the shell message queue. Windows has timeouts to prevent this sort of thing from totally locking up the system but it can cause massive slowdown in affected processes. My solution would be to avoid COM. You could check this by commenting out the parts that actually use COM and timing the process.
I have an interesting problem that I haven't seen documented anywhere else (at least not this specific issue).
This issue is a combination of COM, VB6, and .NET and making them play nice.
Here's what I have:
A legacy VB6 ActiveX DLL (written by us)
A multi-threaded Windows service written in C# that processes requests from clients over the network and sends back results. It does this by creating a new STA thread to handle each request. Each request-handler thread instantiates a COM object (defined in the ActiveX DLL) to process the request and get the result (a string of XML is passed in, and it returns a string of XML back), explicitly releases the COM object, and exits. The service then sends the result back to the client.
All of the network code is handled using asynchronous networking (i.e. thread pool threads).
And yes, I know this is already a risky thing to be doing in the first place, since VB6 isn't very friendly with multi-threaded applications to begin with, but unfortunately it's what I am stuck with for the moment.
I've already fixed a number of things that were causing deadlocks in the code (for example, making sure the COM objects are actually created and called from a separate STA thread, making sure to explicitly release the COM objects before the thread exits to prevent deadlocks that were occurring between the garbage collector and the COM Interop code, etc.), but there is one deadlock scenario that I just can't seem to solve.
With some help from WinDbg, I was able to figure out what is happening, but I'm not sure how (or if) there is a way around this particular deadlock.
What's happening
If one request-handler thread is exiting, and another request-handler thread is starting at the same time, a deadlock can occur because of the way the VB6 runtime initialization and termination routines seem to work.
The deadlock occurs in the following scenario:
The new thread that is starting up is in the middle of creating a new instance of the (VB6) COM object to process an incoming request. At this point, the COM runtime is in the middle of a call to retrieve the object's class factory. The class factory implementation is in the VB6 runtime itself (MSVBVM60.dll). That is, its calling the VB6 runtime's DllGetClassObject function. This, in turn, calls an internal runtime function (MSVBVM60!CThreadPool::InitRuntime), which acquires a mutex and enters a critical section to do part of its work. At this point, it's about to call LoadLibrary to load oleaut32.dll into the process, while holding this mutex. So, now it's holding this internal VB6 runtime mutex and waiting for the OS loader lock.
The thread that is exiting is already running inside the loader lock, because it's done executing managed code and is executing inside the KERNEL32!ExitThread function. Specifically, it's in the middle of handling the DLL_THREAD_DETECH message for MSVBVM60.dll on that thread, which in turn calls a method to terminate the VB6 runtime on the thread (MSVBVM60!CThreadPool::TerminateRuntime). Now, this thread tries to acquire the same mutex that the other thread being initialized already has.
A classic deadlock. Thread A has L1 and wants L2, but Thread B has L2 and needs L1.
The problem (if you've followed me this far) is I don't have any control over what the VB6 runtime is doing in its internal thread initialization and teardown routines.
In theory, if I could force the VB6 runtime initialization code to run inside the OS loader lock, I would prevent the deadlock, because I am fairly certain the mutex the VB6 runtime is holding is specifically only used inside the initialization and termination routines.
Requirements
I can't make the COM calls from a single STA thread, because then the service won't be able to handle concurrent requests. I can't have a long-running request block other client requests either. This is why I create one STA thread per-request.
I need to create a new instance of the COM object on each thread, because I need to make sure each instance has its own copy of global variables in the VB6 code (VB6 gives each thread its own copy of all global variables).
Solutions I've tried that didn't work
Converted ActiveX DLL to ActiveX EXE
First, I tried the obvious solution and created an ActiveX EXE (out-of-process server) to handle the COM calls. Initially, I compiled it so that a new ActiveX EXE (process) was created for each incoming request, and I also tried it with the Thread Per Object compile option (one process instance is created, and it creates each object on a new thread within the ActiveX EXE).
This fixes the deadlock issue with respect to the VB6 runtime, because the VB6 runtime never gets loaded into the .NET code proper. However, this led to a different problem: if concurrent requests come into the service, the ActiveX EXE tends to fail randomly with RPC_E_SERVERFAULT errors. I assume this is because the COM marshalling and/or the VB6 runtime can't deal with concurrent object creation/destruction, or concurrent method calls, inside the ActiveX EXE.
Force the VB6 code to run inside the OS loader lock
Next, I switched back to using an ActiveX DLL for the COM class. To force the VB6 runtime to run its thread initialization code inside the OS loader lock, I created a native (Win32) C++ DLL, with code to handle DLL_THREAD_ATTACH in DllMain. The DLL_THREAD_ATTACH code calls CoInitialize and then instantiates a dummy VB6 class to force the VB6 runtime to be loaded and force the runtime initialization routine to run on the thread.
When the Windows service starts, I use LoadLibrary to load this C++ DLL into memory, so that any threads created by the service will execute that DLL's DLL_THREAD_ATTACH code.
The problem is that this code runs for every thread the service creates, including the .NET garbage collector thread and the thread-pool threads used by the async networking code, which doesn't end well (this just seems to cause the threads to never start properly, and I imagine initializing COM on the GC and thread-pool threads is in general just a very bad idea).
Addendum
I just realized why this is a bad idea (and probably part of the reason it didn't work): it isn't safe to call LoadLibrary when you are holding the loader lock. See Remarks section in this MSDN article: http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx, specifically:
Threads in DllMain hold the loader lock so no additional DLLs can be dynamically loaded or initialized.
Is there any way to workaround these issues?
So, my question is, is there any way to work around the original deadlock issue?
The only other thing I can think of is to create my own lock object and surround the code that instantiates the COM object in a .NET lock block, but then I have no way (that I know of) to put the same lock around the (operating system's) thread exit code.
Is there a more obvious solution to this issue, or am I plain out of luck here?
As long as all of your modules work in one process, you can hook Windows API by replacing some system calls with your wrappers. Then, you can wrap the calls in a single critical section to avoid deadlock.
There are several libraries and samples to achieve that, the technique is commonly known as detouring:
http://www.codeproject.com/Articles/30140/API-Hooking-with-MS-Detours
http://research.microsoft.com/en-us/projects/detours/
And of course the implementation of wrappers should be done in native code, preferably C++. .NET detours work too for high-level API functions such as MessageBox, but if you try to reimplement LoadLibrary API call in .NET then you may get a cyclic dependency issue because .NET runtime internally uses LoadLibrary function during execution and does this often.
So the solution looks like this to me: a separate .DLL module which is loaded at the very start of your application. The module fixes the deadlock problem by patching several VB and Windows API calls with your own wrappers. All wrappers do one thing: wrap the call in critical section and invoke the original API function to do the real job.
EDIT: in retrospect, I don't think this will work. The problem is that the deadlock can occur at any time that a Win32 thread exits, and since Win32 threads don't map 1:1 to .NET threads, we can't (within .NET) force Win32 threads to acquire the lock before exiting. In addition to the possibility of the .NET thread that is exiting being switched to a different OS thread, there are presumably OS threads not associated with any .NET thread (garbage collection and the like) which may start and exit at random.
The only other thing I can think of is to create my own lock object
and surround the code that instantiates the COM object in a .NET lock
block, but then I have no way (that I know of) to put the same lock
around the (operating system's) thread exit code.
That sounds like a promising approach. I gather from this that you
are able to modify the service's code, and you say each thread
explicitly releases the COM object before exiting, so presumably you
could claim a lock at this point, either just before explicitly
releasing the COM object or just after. The secret is to choose a
type of lock that is implicitly released once the thread holding it
has exited, such as a Win32 mutex.
It is likely that a Win32 mutex object does not become abandoned until
the thread has completed all DLL_THREAD_DETACH calls, although I don't
know whether this behaviour is documented. I'm not familiar with
locking in .NET but my guess is that they are unlikely to be suitable,
because even if the right kind of lock exists, it would be likely to
be considered abandoned as soon as the thread reaches the end of the
managed code section, i.e., before the calls to DLL_THREAD_DETACH.
If Win32 mutex objects don't do the trick (or if you very reasonably
prefer not to rely on undocumented behaviour) you might need to
implement the lock yourself. One way to do this would be to use
OpenThread to get a handle to the current thread and save this in your
lock object, along with an event or similar object. If the lock has
been claimed and you want to wait for it to be available, use
WaitForMultipleObjects to wait until either the thread handle or the
event is signaled. If the event is signaled this means the lock has
been explicitly released, if the thread handle is signaled it was
implicitly released by the thread exiting. Obviously implementing
this involves a lot of tricky details (for example: when a thread
explicitly releases the lock, you can't close the thread handle
because another thread might be waiting on it, so you'll have to close
it when the lock is next claimed instead) but it shouldn't be too
difficult to sort these out.
I don't see any reason why you couldn't load an extra instance of the ActiveX control in your startup code and just hang onto the reference. Presto, no more loader lock issues since the VB6 runtime never shuts down.
Since I'm still exploring my options, I wanted to still see if I could implement a solution in pure .NET code without using any native code, for the sake of simplicity. I'm not sure if this is a fool-proof solution yet, because I'm still trying to figure out whether it actually gives me the mutual exclusion I need, or if it just looks like it does.
Any thoughts or comments are welcome.
The relevant part of the code is below. Some notes:
The HandleRpcRequest method is called from a thread-pool thread when a new message is received from a remote client
This fires off a separate STA thread so that it can make the COM call safely
DbRequestProxy is a thin wrapper class around the real COM class I'm using
I used a ManualResetEvent (_safeForNewThread) to provide the mutual exclusion. The basic idea is that this event stays unsignaled (blocking other threads) if any one particular thread is about to exit (and hence potentially about to terminate the VB6 runtime). The event is only signaled again after the current thread completely terminates (after the Join call finishes). This way multiple request-handler threads can still execute concurrently unless an existing thread is exiting.
So far, I think this code is correct and guarantees that two threads can't deadlock in the VB6 runtime initialization/termination code anymore, while still allowing them to execute concurrently for most of their execution time, but I could be missing something here.
public class ClientHandler {
private static ManualResetEvent _safeForNewThread = new ManualResetEvent(true);
private void HandleRpcRequest(string request)
{
Thread rpcThread = new Thread(delegate()
{
DbRequestProxy dbRequest = null;
try
{
Thread.BeginThreadAffinity();
string response = null;
// Creates a COM object. The VB6 runtime initializes itself here.
// Other threads can be executing here at the same time without fear
// of a deadlock, because the VB6 runtime lock is re-entrant.
dbRequest = new DbRequestProxy();
// Call the COM object
response = dbRequest.ProcessDBRequest(request);
// Send response back to client
_messenger.Send(Messages.RpcResponse(response), true);
}
catch (Exception ex)
{
_messenger.Send(Messages.Error(ex.ToString()));
}
finally
{
if (dbRequest != null)
{
// Force release of COM objects and VB6 globals
// to prevent a different deadlock scenario with VB6
// and the .NET garbage collector/finalizer threads
dbRequest.Dispose();
}
// Other request threads cannot start right now, because
// we're exiting this thread, which will detach the VB6 runtime
// when the underlying native thread exits
_safeForNewThread.Reset();
Thread.EndThreadAffinity();
}
});
// Make sure we can start a new thread (i.e. another thread
// isn't in the middle of exiting...)
_safeForNewThread.WaitOne();
// Put the thread into an STA, start it up, and wait for
// it to end. If other requests come in, they'll get picked
// up by other thread-pool threads, so we won't usually be blocking anyone
// by doing this (although we are blocking a thread-pool thread, so
// hopefully we don't block for *too* long).
rpcThread.SetApartmentState(ApartmentState.STA);
rpcThread.Start();
rpcThread.Join();
// Since we've joined the thread, we know at this point
// that any DLL_THREAD_DETACH notifications have been handled
// and that the underlying native thread has completely terminated.
// Hence, other threads can safely be started.
_safeForNewThread.Set();
}
}
I had written a rather complex code using VB6,VC6 about 20 years ago and I need to port it to visual studio.net.
I simply took the functions as I had written them along with the header files corrected all the compile errors (which were MANY) and then tried to load it. got "loaderlock closed"
I then decided to redo all the files starting from those that few other files depended upon and then worked my way up and as I went I included only the header files that that particular file required. The result it loads now just fine. no more loaderlock closed.
the lesson for me is don't include any more header files in a particular cpp file than is absolutely necessary.
hope this helps
from a very happy camper!!
david
I have a ManualResetEvent. At one point, I wait on that event using WaitOne. To my amazement, I received an OnPaint event while in the WaitOne. This happens quite often too.
The stack trace looks like this:
I understood that a WaitOne would block the current thread and would not allow any other code to be executed until the event fires.
Could someone explain what happens here?
This is by design. The CLR honors the contract of a single-threaded apartment (STA). The main thread of a GUI app is STA as is required in Windows programming, the [STAThread] attribute on the Main() method ensures that.
Hard rules for an STA thread are that it must pump a message loop (like Application.Run) and can never block. Blocking an STA thread is highly likely to cause deadlock when background threads use any COM apartment threaded objects. There are many of them, the clipboard and WebBrowser are common ones you'll encounter in a .NET program. Many less visible ones as well, available as .NET wrapper classes.
The CLR ensures blocking can't cause deadlock by pumping a message loop when you use the lock statement or call the Wait method of the synchronization classes. Or Thread.Join(). That message loop dispatches the WM_PAINT message, causing the Paint event to run.
You need to restructure your program to ensure this doesn't cause a problem. Pretty important to focus on not blocking the main thread at all. It is very rarely needed when you have, say, the BackgroundWorker class or Control.BeginInvoke() at your disposal. For some kind of odd reason the Mutex class doesn't do this kind of pumping, that could be another way. Although deadlock is lurking around the corner if you do.
I have seen this behavior too for the lock() statement. Apparently the .net framework Thread classes starts a message loop when waiting for a lock on the UI thread. This just explains what is happening. The reasoning could be to prevent deadlocks when working with legacy STA COM objects. I am not aware of a way to prevent this.