I have an application that does some excel automation through an automation add in.
This add-in is multithreaded, and all the threads manage to make calls to the excel COM objects. Because excel can sometimes return a "is busy" exception when making multiple calls, i have wrapped all my calls in a "retry" function. However i feel this is inneficient.
I am now trying to make all the calls to excel objects on the same thread, so that all calls are "serialized" by me, therefore reducing the risk of excel returning a "is busy" exception.
However when this thread tries to access an excel object, the application hangs. I have tried setting the thread to STA or MTA to no avail.
The code i use to launch everything from a single thread is as follows:
The "offending" part should be in "DoPass",maybe the way i am invoking the Delegate is somehow wrong.
public static class ExcelConnector
{
public static Thread _thread;
private static int ticket;
public static Dictionary<Delegate, int> actionsToRun = new Dictionary<Delegate, int>();
public static Dictionary<int, object> results = new Dictionary<int, object>();
static ExcelConnector()
{
LaunchProcess();
}
public static int AddMethodToRun(Delegate method)
{
lock (actionsToRun)
{
ticket++;
actionsToRun.Add(method, ticket);
}
return ticket;
}
public static bool GetTicketResult(int ticket, out object result)
{
result = null;
if (!results.ContainsKey(ticket))
return false;
else
{
result = results[ticket];
lock (results)
{
results.Remove(ticket);
}
return true;
}
}
public static void LaunchProcess()
{
_thread = new Thread(new ThreadStart(delegate
{
while (true)
{
DoPass();
}
}));
// _thread.SetApartmentState(ApartmentState.STA);
// _thread.IsBackground = true;
_thread.Start();
}
public static void DoPass()
{
try
{
Logger.WriteLine("DoPass enter");
Dictionary<Delegate, int> copy;
lock (actionsToRun)
{
copy = new Dictionary<Delegate, int>(actionsToRun);
}
//run
foreach (var pair in copy)
{
object res = pair.Key.Method.Invoke(
pair.Key.Target, null);
lock (results)
{
results[pair.Value] = res;
}
lock (actionsToRun)
{
actionsToRun.Remove(pair.Key);
}
Thread.Sleep(100);
}
}
catch (Exception e)
{
Logger.WriteError(e);
//mute
}
}
}
EDIT: the error can be reproduced in a simple test (the readline is just there to give time to the ExcelConnector thread to work):
var excelApp = new Application();
excelApp = new Application();
excelApp.Visible = true;
excelApp.DisplayAlerts = false;
System.Action act = delegate
{
string s = excelApp.Caption;
Console.WriteLine(s);
};
ExcelConnector.AddMethodToRun(act);
Console.ReadLine();
Unfortunately there is no point in what you are doing, this is already being done. The Office interop is based on out-of-process COM. Like many COM interfaces, the Excel interfaces are marked as apartment threaded in the registry. Which is an expensive way of saying they don't support threads.
COM automatically takes care of components that don't support threading, it automatically marshals calls made on a worker thread to the thread that created the COM object. Which should be a thread that's STA, like the main thread of any program that has a user interface. It will create an STA thread automatically if necessary. One side effect of this marshaling is that the calls made by the worker threads are automatically serialized. After all, the STA thread can only dispatch one call at a time.
Another side-effect is that deadlock is not uncommon. Which will happen when the STA thread stays busy and doesn't pump the message loop. The marshaling is done by COM plumbing code that relies on the message loop to dispatch the calls. This condition is pretty easy to debug, you'd use Debug + Break All, Debug + Windows + Threads and check what the STA (or Main) thread is busy with.
Also beware that attempting this kind of threading is probably 90% of the reason you get this interop exception in the first place. Trying to get code that's fundamentally thread-unsafe to do more than one thing at the same time just doesn't work well. You'd avoid the "is busy" exception from Excel by interlocking your own code, marking an operation that puts Excel in that 'busy' state so you back-off other threads. Painful to do of course.
You have to initialize COM in each thread you wish to use your COM library. From the documentation of CoInitializeEx "CoInitializeEx must be called at least once, and is usually called only once, for each thread that uses the COM library.".
Instead of trying to implement your own threading perhaps you should check .NET's Task Parallel Library. Check this question on using COM objects from TPL. Essentially, you just create Task objects and submit them to an StaTaskScheduler for execution. The scheduler manages the creation and disposal of threads, raising exceptions etc.
I'm not really knowledgeable about C#, but my guess is that you still have to initialize COM in some way when starting a new thread in order to have a message box which can be used to signal your thread when the operation completed.
It's usually not necessary to initialize COM in .NET -- unless you've done some native things such as P/Invoking. Using IDispatch does not require explicit initialization of COM.
I think you're just dead locking somewhere. Fire up your debugger, when it hangs, break in, and type Monitor.TryEnter(...) for each of the object that you can lock (actionsToRun, results and others).
BTW, you should really consider restructuring your application to not use Excel concurrently -- even if you do some kind of "serialization". Even if you get it work, it will come back and bite you forever. It's officially discouraged, and I speak from experience.
Related
I've been working with a third party SDK as a referenced dll from within C# using .NET 4.5.2 on Windows 10. The IDE creates an Interop around the dll and I can see the appropriate namespaces, interfaces, enum, etc. The SDK I am working with is for the Blackmagic ATEM Television Studio, but I don't think that is directly relevant.
The SDK provides an object I can use to locate/discover the attached hardware and returns an instance of an object, which appears to be a wrapper (RCW) around the underlying COM object.
The discovery code looks like this:
string address = "192.168.1.240";
_BMDSwitcherConnectToFailure failureReason = 0;
IBMDSwitcher switcher = null;
var discovery = new CBMDSwitcherDiscovery();
discovery.ConnectTo(address, out switcher, out failureReason);
If I perform this code on my WPF UI thread, which is an STA apartment, it will work without any problem. I am able to use the object without error. However, if I try to access the resulting switcher object from any new thread (STA or MTA) I will receive an error similar to the following:
Unable to cast COM object of type 'System.__ComObject' to interface
type 'BMDSwitcherAPI.IBMDSwitcherMixEffectBlock'. This operation
failed because the QueryInterface call on the COM component for the
interface with IID '{11974D55-45E0-49D8-AE06-EEF4D5F81DF6}' failed due
to the following error: No such interface supported (Exception from
HRESULT: 0x80004002 (E_NOINTERFACE)).
Quoting from MikeJ and his answer to a similar question here:
This nasty, nasty exception arises because of a concept known as COM
marshalling. The essence of the problem lies in the fact that in order
to consume COM objects from any thread, the thread must have access to
the type information that describes the COM object.
At this point I decided to adapt my strategy slightly and try calling the discovery logic from within an MTA thread. Like this:
private IBMDSwitcher _switcher = null;
public void Connect()
{
Task.Run(() =>
{
string address = "192.168.1.240";
IBMDSwitcherDiscovery discovery = new CBMDSwitcherDiscovery();
_BMDSwitcherConnectToFailure failureReason = 0;
discovery.ConnectTo(address, out _switcher, out failureReason);
});
}
This seems to work but at a cost.
The tradeoff is that I can now work with my switcher object from any background (MTA) thread without problem, but my entire application will simply crash after running for approximately 15 minutes. Before someone says it, I know this isn't thread-safe. I recognize the need for some synchronization logic before multiple MTA threads try to use my switcher object. But that's down the road, right now if I run the above code and simply let the application idle for 15 minutes, it will crash, every time.
So on one hand I have a stable app but I can only use the library from the UI thread and on the other hand I have an unstable app but I can use the library from any (MTA) background thread.
Due to the nature of my app, it would be preferable to be able to use the library from multiple background threads. For example, one thread might be generating and uploading graphics to the device, while another thread is managing switching video inputs, and a third thread is managing audio inputs, and the UI thread is handling ID-10T bonk dialogs... All of this could be done from the UI thread, but I'd really rather avoid that if possible.
And so: Is there some way I can discover and create my switcher object on the UI (STA) thread (and theoretically avoid blowing up in 15 minutes) but make the type information accessible to my background (MTA) threads so they can also use the switcher? Or alternately, is it safe to discover/create my switcher object on a background (MTA) thread but I need to do something to 'mark' it in some special way to avoid that 15 minute blow-up?
EDIT:
After reading the comment by Hans Passant and investigating the link he provided, I adapted the referenced STAThread class for my own use in WPF. But I'm a bit fuzzy on SynchronizationContext's and Dispatcher's. Would my code listed below be safe to use as a wrapper 'around' my COM object without blocking the UI during any 'long running' operations? My use case would be to have a Task() running that would prep some data, then Invoke some code to interact with my COM object and when the operation is complete code flow resumes in the running Task to perform the next series of operations...
public class STAThread
{
private Thread thread;
private SynchronizationContext ctx;
private ManualResetEvent mre;
public STAThread()
{
using (mre = new ManualResetEvent(false))
{
thread = new Thread(() =>
{
ctx = new SynchronizationContext();
mre.Set();
Dispatcher.Run();
});
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
mre.WaitOne();
}
}
public void BeginInvoke(Delegate dlg, params Object[] args)
{
if (ctx == null) throw new ObjectDisposedException("STAThread");
ctx.Post((_) => dlg.DynamicInvoke(args), null);
}
public object Invoke(Delegate dlg, params Object[] args)
{
if (ctx == null) throw new ObjectDisposedException("STAThread");
object result = null;
ctx.Send((_) => result = dlg.DynamicInvoke(args), null);
return result;
}
}
I have written a Side-By-Side COM DLL in C#.
I am using this DLL in VB6.
The COM DLL contains a thread.
As soon as I start this thread, the calling application (in my case VB6) blocks (meaning I can not do anything in it anymore).
I am starting the thread like this:
private Thread _startMasterThread;
public void Init()
{
if (_startMasterThread == null)
{
_startMasterThread = new Thread(new ThreadStart(pMasterThread));
_startMasterThread.Priority = ThreadPriority.Highest;
_startMasterThread.Start();
}
}
private void pMasterThread()
{
while (!_bAbortAll)
{
//do something
}
}
ThreadStart comes from this:
namespace System.Threading
{
[ComVisible(true)]
public delegate void ThreadStart();
}
Is it normal that the calling application becomes unresponsive?
I thought that since it is a different thread, it would not do this.
It looks like you create a STA thread and then neglect to serve the message pump. Callers will block because nobody responds to their messages. Hence, the UI (a caller) freezes (block).
Some old, but highly relevant articles:
Understanding and Using COM Threading Models
Single-Threaded Apartments
Apartments and Pumping in the CLR
After you read these, and understand the issue, the solution(s) will be obvious. Switch to an MTA or run a message pump in your thread.
I am using BackgroundWorker and inside it I am using foreach loop, inside which i create new thread, wait for it to finish, and than report progress and continue foreach loop. Here is what I am talking about:
private void DoWork(object sender, DoWorkEventArgs e) {
var fileCounter = Convert.ToDecimal(fileNames.Count());
decimal i = 0;
foreach (var file in fileNames) {
i++;
var generator = new Generator(assembly);
var thread = new Thread(new ThreadStart(
delegate() {
generator.Generate(file);
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while (thread.IsAlive); // critical point
int progress = Convert.ToInt32(Math.Round(i / fileCounter * 100));
backgroundWorker.ReportProgress(progress);
}
}
The problem is that memory is not being freed after thread finishes (after "critical point" line is passed). I thought that when thread is not alive, all resources associated with it will be released. But apparently this is not true.
Can anyone explain to me why and what am I doing wrong.
Thanks.
You managed to shut up the component telling you that you were doing something wrong. You however didn't actually fix the problem. An STA, Single Threaded Apartment, is required by components that do not support threading. So that all of its methods are called from the same thread, even if the call was made on another thread. COM takes care of marshaling the call from one thread to another. An STA thread makes that possible by pumping a message loop.
What you did however is create another thread and make calls on it, distinct from the thread on which the generator object was created. This doesn't solve the problem, it is still thread-unsafe. COM still marshals the call.
What matters a great deal is the thread on which you created the generator object. Since it is an apartment threaded object, it must be created on an STA thread. There normally is only one in a Windows app, the main thread of your program, otherwise commonly known as the UI thread. If you create it on a .NET worker thread that isn't STA, like you do here, then COM will step in and create an STA thread itself to give the component a hospitable home. This is nice but usually undesirable.
There's no free lunch here, you cannot magically make a chunk of code that explicitly says it doesn't (the ThreadingModel key in the registry) support threading behave like it does. Your next best bet is to create an STA thread and run all of the code on it, including the COM object creation. Beware that you typically have to pump a message loop with Application.Run(), many COM servers assume there's one available. Especially when they tell you that an STA thread is required. You'll notice that they do when they misbehave, deadlocking on a method call or not raising events.
Regarding your original question, this is standard .NET behavior. The garbage collector runs when it needs to, not when you think it should. You can override it with GC.Collect() but that's very rarely necessary. Although it might be a quick fix in your case, COM creates a new thread for every single file. The STA thread to give the generator a home. Use Debug + Windows + Threads to see them. These threads won't stop until the COM object is destroyed. Which requires the finalizer thread to run. Your code will also consume all available memory and bomb with OOM when there are more than two thousand files, perhaps reason enough to look for a real fix.
This might be cause garbage collection is not immediate. Try to collect after the thread goes out of scope:
Edit:
You also need to implement a better way to wait for the thread to finish other then busy wait(while (thread.IsAlive);) to save CPU time, you can use AutoResetEvent.
private void DoWork(object sender, DoWorkEventArgs e) {
var fileCounter = Convert.ToDecimal(fileNames.Count());
decimal i = 0;
var Event = new AutoResetEvent(false);
foreach (var file in fileNames) {
i++;
var generator = new Generator(assembly);
{
var thread = new Thread(new ThreadStart(
delegate() {
generator.Generate(file);
Event.Set();
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
//while (thread.IsAlive); // critical point
Event.WaitOne();
}
GC.Collect();
int progress = Convert.ToInt32(Math.Round(i / fileCounter * 100));
backgroundWorker.ReportProgress(progress);
}
}
Do Generate method get data from UI controls?
I have a program that uses threads to perform time-consuming processes sequentially. I want to be able to monitor the progress of each thread similar to the way that the BackgroundWorker.ReportProgress/ProgressChanged model does. I can't use ThreadPool or BackgroundWorker due to other constraints I'm under. What is the best way to allow/expose this functionality. Overload the Thread class and add a property/event? Another more-elegant solution?
Overload the Thread class and add a
property/event?
If by "overload" you actually mean inherit then no. The Thread is sealed so it cannot be inherited which means you will not be able to add any properties or events to it.
Another more-elegant solution?
Create a class that encapsulates the logic that will be executed by the thread. Add a property or event (or both) which can be used to obtain progress information from it.
public class Worker
{
private Thread m_Thread = new Thread(Run);
public event EventHandler<ProgressEventArgs> Progress;
public void Start()
{
m_Thread.Start();
}
private void Run()
{
while (true)
{
// Do some work.
OnProgress(new ProgressEventArgs(...));
// Do some work.
}
}
private void OnProgress(ProgressEventArgs args)
{
// Get a copy of the multicast delegate so that we can do the
// null check and invocation safely. This works because delegates are
// immutable. Remember to create a memory barrier so that a fresh read
// of the delegate occurs everytime. This is done via a simple lock below.
EventHandler<ProgressEventArgs> local;
lock (this)
{
var local = Progress;
}
if (local != null)
{
local(this, args);
}
}
}
Update:
Let me be a little more clear on why a memory barrier is necessary in this situation. The barrier prevents the read from being moved before other instructions. The most likely optimization is not from the CPU, but from the JIT compiler "lifting" the read of Progress outside of the while loop. This movement gives the impression of "stale" reads. Here is a semi-realistic demonstration of the problem.
class Program
{
static event EventHandler Progress;
static void Main(string[] args)
{
var thread = new Thread(
() =>
{
var local = GetEvent();
while (local == null)
{
local = GetEvent();
}
});
thread.Start();
Thread.Sleep(1000);
Progress += (s, a) => { Console.WriteLine("Progress"); };
thread.Join();
Console.WriteLine("Stopped");
Console.ReadLine();
}
static EventHandler GetEvent()
{
//Thread.MemoryBarrier();
var local = Progress;
return local;
}
}
It is imperative that a Release build is ran without the vshost process. Either one will disable the optimization that manifest the bug (I believe this is not reproducable in framework version 1.0 and 1.1 as well due to their more primitive optimizations). The bug is that "Stopped" is never displayed even though it clearly should be. Now, uncomment the call to Thread.MemoryBarrier and notice the change in behavior. Also keep in mind that even the most subtle changes to the structure of this code currently inhibit the compiler's ability to make the optimization in question. One such change would be to actually invoke the delegate. In other words you cannot currently reproduce the stale read problem using the null check followed by an invocation pattern, but there is nothing in the CLI specification (that I am aware of anyway) that prohibits a future hypothetical JIT compiler from reapplying that "lifting" optimization.
I tried this some time ago and it worked for me.
Create a List-like class with locks.
Have your threads add data to an instance of the class you created.
Place a timer in your Form or wherever you want to record the log/progress.
Write code in the Timer.Tick event to read the messages the threads output.
You might also want to check out the Event-based Asynchronous Pattern.
Provide each thread with a callback that returns a status object. You can use the thread's ManagedThreadId to keep track of separate threads, such as using it as a key to a Dictionary<int, object>. You can invoke the callback from numerous places in the thread's processing loop or call it from a timer fired from within the thread.
You can also use the return argument on a callback to signal the thread to pause or halt.
I've used callbacks with great success.
I would like to start x number of threads from my .NET application, and I would like to keep track of them as I will need to terminate them manually or when my application closes my application later on.
Example ==> Start Thread Alpha, Start Thread Beta .. then at any point in my application I should be able to say Terminate Thread Beta ..
What is the best way to keep track of opened threads in .NET and what do I need to know ( an id ? ) about a thread to terminate it ?
You could save yourself the donkey work and use this Smart Thread Pool. It provides a unit of work system which allows you to query each thread's status at any point, and terminate them.
If that is too much bother, then as mentioned anIDictionary<string,Thread> is probably the simplest solution. Or even simpler is give each of your thread a name, and use an IList<Thread>:
public class MyThreadPool
{
private IList<Thread> _threads;
private readonly int MAX_THREADS = 25;
public MyThreadPool()
{
_threads = new List<Thread>();
}
public void LaunchThreads()
{
for (int i = 0; i < MAX_THREADS;i++)
{
Thread thread = new Thread(ThreadEntry);
thread.IsBackground = true;
thread.Name = string.Format("MyThread{0}",i);
_threads.Add(thread);
thread.Start();
}
}
public void KillThread(int index)
{
string id = string.Format("MyThread{0}",index);
foreach (Thread thread in _threads)
{
if (thread.Name == id)
thread.Abort();
}
}
void ThreadEntry()
{
}
}
You can of course get a lot more involved and complicated with it. If killing your threads isn't time sensitive (for example if you don't need to kill a thread in 3 seconds in a UI) then a Thread.Join() is a better practice.
And if you haven't already read it, then Jon Skeet has this good discussion and solution for the "don't use abort" advice that is common on SO.
You can create a Dictionary of threads and assign them id's, like:
Dictionary<string, Thread> threads = new Dictionary<string, Thread>();
for(int i = 0 ;i < numOfThreads;i++)
{
Thread thread = new Thread(new ThreadStart(MethodToExe));
thread.Name = threadName; //Any name you want to assign
thread.Start(); //If you wish to start them straight away and call MethodToExe
threads.Add(id, thread);
}
If you don't want to save threads against an Id you can use a list and later on just enumerate it to kill threads.
And when you wish to terminate them, you can abort them. Better have some condition in your MethodToExe that allows that method to leave allowing the thread to terminate gracefully. Something like:
void MethodToExe()
{
while(_isRunning)
{
//you code here//
if(!_isRunning)
{
break;
}
//you code here//
}
}
To abort you can enumerate the dictionary and call Thread.Abort(). Be ready to catch ThreadAbortException
I asked a similar questions and received a bunch of good answers: Shutting down a multithreaded application
Note: my question did not require a graceful exit, but people still recommended that I gracefully exit from the loop of each thread.
The main thing to remember is that if you want to avoid having your threads prevent your process from terminating you should set all your threads to background:
Thread thread = new Thread(new ThreadStart(testObject.RunLoop));
thread.IsBackground = true;
thread.start();
The preferred way to start and manage threads is in a ThreadPool, but just about any container out there can be used to keep a reference to your threads. Your threads should always have a flag that will tell them to terminate and they should continually check it.
Furthermore, for better control you can supply your threads with a CountdownLatch: whenever a thread is exiting its loop it will signal on a CountdownLatch. Your main thread will call the CountdownLatch.Wait() method and it will block until all the threads have signaled... this allows you to properly cleanup and ensures that all your threads have shutdown before you start cleaning up.
public class CountdownLatch
{
private int m_remain;
private EventWaitHandle m_event;
public CountdownLatch(int count)
{
Reset(count);
}
public void Reset(int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException();
m_remain = count;
m_event = new ManualResetEvent(false);
if (m_remain == 0)
{
m_event.Set();
}
}
public void Signal()
{
// The last thread to signal also sets the event.
if (Interlocked.Decrement(ref m_remain) == 0)
m_event.Set();
}
public void Wait()
{
m_event.WaitOne();
}
}
It's also worthy to mention that the Thread.Abort() method does some strange things:
When a thread calls Abort on itself,
the effect is similar to throwing an
exception; the ThreadAbortException
happens immediately, and the result is
predictable. However, if one thread
calls Abort on another thread, the
abort interrupts whatever code is
running. There is also a chance that a
static constructor could be aborted.
In rare cases, this might prevent
instances of that class from being
created in that application domain. In
the .NET Framework versions 1.0 and
1.1, there is a chance the thread could abort while a finally block is
running, in which case the finally
block is aborted.
The thread that calls Abort might
block if the thread that is being
aborted is in a protected region of
code, such as a catch block, finally
block, or constrained execution
region. If the thread that calls Abort
holds a lock that the aborted thread
requires, a deadlock can occur.
After creating your thread, you can set it's Name property. Assuming you store it in some collection you can access it conveniently via LINQ in order to retrieve (and abort) it:
var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault();
if(myThread != null)
myThread.Abort();
Wow, there are so many answers..
You can simply use an array to hold the threads, this will only work if the access to the array will be sequantial, but if you'll have another thread accessing this array, you will need to synchronize access
You can use the thread pool, but the thread pool is very limited and can only hold fixed amount of threads.
As mentioned above, you can create you own thread pool, which in .NET v4 becomes much easier with the introduction of safe collections.
you can manage them by holding a list of mutex object which will determine when those threads should finish, the threads will query the mutex each time they run before doing anything else, and if its set, terminate, you can manage the mutes from anywhere, and since mutex are by defenition thread-safe, its fairly easy..
i can think of another 10 ways, but those seems to work. let me know if they dont fit your needs.
Depends on how sophisticated you need it to be. You could implement your own type of ThreadPool with helper methods etc. However, I think its as simple as just maintaining a list/array and adding/removing the threads to/from the collection accordingly.
You could also use a Dictionary collection and use your own type of particular key to retrieve them i.e. Guids/strings.
As you start each thread, put it's ManagedThreadId into a Dictionary as the key and the thread instance as the value. Use a callback from each thread to return its ManagedThreadId, which you can use to remove the thread from the Dictionary when it terminates. You can also walk the Dictionary to abort threads if needed. Make the threads background threads so that they terminate if your app terminates unexpectedly.
You can use a separate callback to signal threads to continue or halt, which reflects a flag set by your UI, for a graceful exit. You should also trap the ThreadAbortException in your threads so that you can do any cleanup if you have to abort threads instead.