开发者

Proper thread termination in multi-threaded C# application

开发者 https://www.devze.com 2022-12-28 12:38 出处:网络
I have what I think is a rather complex problem.I have a C# applica开发者_如何学Pythontion that utilizes a plug-in architecture using reflection.The application loads plug-in dlls and the user is able

I have what I think is a rather complex problem. I have a C# applica开发者_如何学Pythontion that utilizes a plug-in architecture using reflection. The application loads plug-in dlls and the user is able to enable/disable them. When a plug-in is enabled, the main app starts a thread to run the plug-in in. In many cases the plug-in may have multiple threads of its own. When I want to disable a plug-in I am calling Thread.Abort(). This seems to kill the initial thread that was created for the plug-in, but any additional threads that the plug-in created continue running. Is there a better way to stop all of the associated plug-in's threads along with the main thread?

Thanks.


Don't use Thread.Abort for this purpose.

Add a Shutdown method or similar to your plugin API and ask your plugins to shutdown cleanly. If you need to protect yourself against rogue plugins that refuse to shutdown then run them in their own AppDomain and kill the AppDomain if necessary.


I would set a flag in the plugin that I wish to close it, and the plugin itself should periodically check to see if the flag is set and if so, it should clean up after itself. This aproach works best with a while(true) {...} kind of thread body.

If instead you're using an event-based aproach with a lot of WaitForSingleObject, I would use an event that I'd pulse when I want the plugin to shut down, and I'd add the event to a WaitForMultipleObjects list to be checked.

It really depends on how your plugin is running and how exactly it's coded. Try providing more information.

Thread.Abort is a horrible way to do it, it doesn't run any cleanup at all.


Yeah, don't use Abort. I'd use a ManualResetEvent to signal when I want to terminate the execution, e.g. with a loop:

ManualResetEvent _stopping = new ManualResetEvent(false);
...
while (!_stopping.WaitOne(0))
{
    ...
}

And signal when you want to stop the loop:

public void Stop()
{
    _stopping.Set();
}

Then use Thread.Join, if you want to wait until the thread terminates. If it doesn't in a timely fashion you then could call Abort.

In your case you should REALLY load the add-ins in a separate AppDomain and unload it when you are done. You may want to architecture a model in which you also send to the add-ins notifications when they are about to be shutdown.


First, you really should avoid using Thread.Abort as a means to terminate a thread. I don't know if you have control over the implementatio of the plug-in, but if you do you should reconsider that design. Read this and this for more details about the problems related to Thread.Abort.

As for how to have other threads stop that the plug-in creates, again - you want to design an interface between your code and the plug in that gracefully informs the plug in that you would like it to stop what it's doing.


I know of no way to interrogate a Thread for clues about who may claim to be its owner. That basically means you will need to add the approriate mechanisms to your plugin API for shutting down an instance of plugin. Maybe you could add a Shutdown or Terminate method to the plugin interface and make it part of documented contract that imlementers must play nice and cleanup all resources they allocate.

The only other strategy I can think of (and this one sucks big time) is to keep track of all the threads your application creates on its own and then assume that all others are owned by plugins. You would have to abort all of those threads since you would not be able to link them to specific instances of a plugin. Personally, this sounds like a recipe for disaster. I would only explore this as a last resort.


It sounds to me like you're calling arbitrary methods on various assemblies that may not have been designed to be run on a thread with the expectation that they may be cancelled.
The plug-in method that you run on it's own thread should at least be handling exceptions and cleaning up it's own threads. When Thread.Abort() is called on the thread, a ThreadAbortException is thrown on that thread to terminate it.

Thread.Abort() is not the recommended way to terminate a thread under normal conditions. A better approach is to have a cooperative way designed into the method that allows you to cancel it. If that's not possible, calling Thread.Interrupt() is a gentler way to terminate the thread as long as the executing method occasionally enters a WaitSleepJoin state (waiting on an WaitHandle, sleeping, etc.) at safe points. In that case, a ThreadInterruptedException is thrown on the thread. The other threads should still be cleaned up in an exception handler.


The other guys are right - code in a graceful shutdown signal. However, if you can't readily change the child threads' code, and you're under awful schedule pressure, and if there's little chance that the child threads will reset or hang on an abort, and you promise to refactor this later, then you could add a fail-safe to your plugin that adds child threads to a collection, and then trap the ThreadAbortException and walk the collection aborting the child threads.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号