我想从我的.NET应用程序中启动x个线程,我想跟踪它们,因为我需要手动终止它们,或者我的应用程序稍后关闭我的应用程序。
示例==>启动线程Alpha,启动线程测试..然后在我的应用程序的任何点,我应该能够说终止线程测试..
跟踪.NET中打开的线程的最佳方法是什么?我需要知道什么(一个id?)关于终止它的线程? 示例代码,教程会有所帮助。
答案 0 :(得分:15)
你可以节省自己的驴工作并使用 Smart Thread Pool 。它提供了一个工作单元系统,允许您在任何时候查询每个线程的状态,并终止它们。
如果这太麻烦了,那么提到IDictionary<string,Thread>
可能是最简单的解决方案。或者更简单的是为每个线程命名,并使用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()
{
}
}
你当然可以更多地参与其中并使其复杂化。如果杀死你的线程不是时间敏感的(例如,如果你不需要在UI中3秒内杀死一个线程),那么Thread.Join()是一种更好的做法。
如果你还没有读过它,那么Jon Skeet this good discussion and solution就那些在SO上常见的“不要使用中止”的建议而言。
答案 1 :(得分:3)
你可以创建一个线程词典并为它们分配id,如:
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);
}
如果你不想针对Id保存线程,你可以使用一个列表,稍后只需枚举它就可以杀死线程。
当您希望终止它们时,您可以中止它们。最好在MethodToExe
中有一些允许该方法允许线程正常终止的条件。类似的东西:
void MethodToExe()
{
while(_isRunning)
{
//you code here//
if(!_isRunning)
{
break;
}
//you code here//
}
}
要中止,您可以枚举字典并致电Thread.Abort()
。准备好抓住ThreadAbortException
答案 2 :(得分:3)
我问过类似的问题并得到了很多好的答案:Shutting down a multithreaded application
注意:我的问题不需要优雅退出,但人们仍然建议我优雅地退出每个线程的循环。
要记住的主要事情是,如果你想避免线程阻止你的进程终止,你应该将所有线程设置为后台:
Thread thread = new Thread(new ThreadStart(testObject.RunLoop));
thread.IsBackground = true;
thread.start();
启动和管理线程的首选方法是ThreadPool
,但几乎任何容器都可以用来保存对线程的引用。你的主题应该总是有一个标志,告诉他们终止,他们应该不断检查它。
此外,为了更好地控制,您可以为线程提供CountdownLatch
:当线程退出其循环时,它将在CountdownLatch
上发出信号。您的主线程将调用CountdownLatch.Wait()
方法,它将阻塞,直到所有线程都已发出信号...这样您就可以正确清理并确保在开始清理之前所有线程都已关闭。
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();
}
}
值得一提的是,Thread.Abort()方法做了一些奇怪的事情:
当一个线程调用Abort时, 效果类似于抛出一个 例外; ThreadAbortException 立即发生,结果是 可预测的。但是,如果一个线程 在另一个线程上调用Abort ,. 中止任何代码都会中断 运行。还有一个机会 静态构造函数可以中止。 在极少数情况下,这可能会阻止 该类的实例 在该应用程序域中创建。在 .NET Framework版本1.0和 1.1,有一个机会线程可以在最后一个块时中止 运行,在这种情况下终于 块被中止。
调用Abort的线程可能 阻止正在进行的线程 流产是在受保护的地区 代码,例如catch块,最后 阻止或约束执行 区域。如果是调用Abort的线程 持有一个被中止线程的锁 要求,可能会发生僵局。
答案 3 :(得分:2)
创建线程后,您可以设置它的Name属性。假设您将它存储在某个集合中,您可以通过LINQ方便地访问它以便检索(并中止)它:
var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault();
if(myThread != null)
myThread.Abort();
答案 4 :(得分:1)
取决于您需要它的复杂程度。您可以使用辅助方法等实现自己的ThreadPool类型。但是,我认为它就像维护列表/数组并相应地向集合中添加/删除线程一样简单。
您还可以使用Dictionary集合并使用您自己的特定键类型来检索它们,即Guids / strings。
答案 5 :(得分:1)
我可以想到另外10种方法,但这些似乎有效。如果他们不符合您的需求,请告诉我。
答案 6 :(得分:1)
当你启动每个线程时,将它的ManagedThreadId作为键放入Dictionary中,将线程实例作为值。使用每个线程的回调来返回其ManagedThreadId,您可以使用该ManagedThreadId在终止时从Dictionary中删除该线程。如果需要,您还可以使用Dictionary来中止线程。使线程成为后台线程,以便在应用程序意外终止时终止它们。
您可以使用单独的回调来指示线程继续或暂停,这反映了UI设置的标志,以便正常退出。您还应该在线程中捕获ThreadAbortException,以便在必须中止线程时可以进行任何清理。