如何杀死C#线程?

我有一个线程,在我们的(旧)SQL服务器上查找数据。

随着数据的进入,我将信息发布到modal dialog – 在进行所有这些处理时,用户不能也不应该做任何其他事情。 modal dialog只是让他们看到我正在做某事并阻止他们同时运行另一个查询。

有时(很少)当代码调用SQL服务器时,服务器没有响应(IT将其关闭以进行维护,LAN线被切断,或者PC不在网络上)或执行查询的人没时间了。 因此,modal dialog确实有一个取消按钮。

Thread对象(System.Threading.Thread)具有IsBackground=true

当有人点击取消时,我会调用我的KillThread方法。

注意:我不能在此类中使用BackgroundWorker组件,因为它与某些Windows Mobile 5代码共享,而WM5没有BackgroundWorker。

 void KillThread(Thread th) { if (th != null) { ManualResetEvent mre = new ManualResetEvent(false); Thread thread1 = new Thread( () => { try { if (th.IsAlive) { //th.Stop(); // 'System.Threading.Thread' does not contain a definition for 'Stop' // and no extension method 'Stop' accepting a first argument of type // 'System.Threading.Thread' could be found (are you missing a using // directive or an assembly reference?) th.Abort(); } } catch (Exception err) { Console.WriteLine(err); } finally { mre.Set(); } } ); string text = "Thread Killer"; thread1.IsBackground = true; thread1.Name = text; thread1.Start(); bool worked = mre.WaitOne(1000); if (!worked) { Console.WriteLine(text + " Failed"); } th = null; } } 

在我的输出窗口中,我总是看到“线程杀手失败”但是没有抛出任何exception。

我该如何停止线程?

我找到的最好的相关post在下面两个:

如何在C#中杀死线程?
如何在C#中立即杀死一个线程?

编辑:

似乎与我上面列出的方法有些混淆。

首先,当有人点击取消按钮时,会调用此例程:

 void Cancel_Click(object sender, EventArgs e) { KillThread(myThread); } 

接下来,当我进入杀死一个线程时,我宁愿不必等待线程停止。 同时,如果线程仍处于活动状态,我不想让我的代码继续运行。 所以,我使用ManualResetEvent对象。 它不应该花费整秒(1000毫秒)来停止一个线程,但每次WaitOne方法都会超时。

还在听取意见。

简答:你没有。 通常,您通过发信号通知您要退出。 如果您正在触发SQL查询,请异步执行(原谅我的拼写),并在必要时取消它。 这真的适用于单独线程中的任何冗长的任务。

有关进一步阅读,请参阅Eric Lippert的文章: 小心斧头,第一部分:我应该指定超时吗? 第二部分:关注那个斧头:例外情况怎么样?

编辑:你如何调用SQL Server? ADO,TDS,标准/自定义库等……? 这个电话应该是asynchrone。 因此:StartOpeningConnection,WaitFor OpeningComplete,StartQuery,WaitFor QueryComplete,Start CloseConnection,WaitFor CloseConnectionComplete等。在任何等待期间,您的线程应该hibernate。 唤醒后,检查您的父线程(UI线程)是否已取消,或者是否已发生超时并退出线程并可能通知sqlserver您已完成(关闭连接)。

这并不容易,但很少……

编辑2 :在您的情况下,如果您无法将数据库代码更改为asynchrone,请将其设置为单独的进程并在必要时将其删除。 这样就可以释放资源(连接等)。 对于线程,情况并非如此。 但这是一个丑陋的黑客

编辑3:您应该使用BeginExecuteReader / EndExecuteReader模式。 这篇文章是一个很好的参考:它需要重写您的数据访问代码,但这是正确的方法。

我觉得让线程1000毫秒中止是不够的。 MSDN建议您调用Thread.Join。 查看正在中止的代码肯定会有所帮助。

Thread.Abort的

线程不保证立即中止,或者根本不中止。 如果线程在作为中止过程的一部分调用的finally块中执行无限量的计算,则会发生这种情况,从而无限期地延迟中止。 要等到线程中止,可以在调用Abort方法后调用线程上的Join方法,但不能保证等待将结束。

你在KillThread方法中传递了什么? 将在UI线程上单击取消按钮,而不是您要杀死的线程。

当用户单击“取消”(而不是终止该线程)时,您应该发出事件信号。 在您的示例中,ManualResetEvent“mre”的范围应该在线程函数之外。