2011-02-17 183 views
5

我有一个线程出去查找我们的(旧)SQL服务器上的数据。如何杀死一个C#线程?

随着数据的进入,我发布信息到一个模式对话框 - 用户不能做任何事情,而所有这些处理都在进行。模态对话框只是为了让他们看到我正在做一些事情,并阻止他们同时运行另一个查询。

有时(很少),当代码调用SQL服务器时,服务器不响应(IT维护人员维护它,LAN线路被切断或PC不在网络中)或者做查询的人用完了时间。所以,模式对话框确实有一个取消按钮。

线程对象(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; 
    } 
} 

在我的输出窗口,我总是看到“主题杀手失败”,但没有异常丢进。

我应该如何停止一个线程?

最好相关的帖子,我发现其中两个以下:

How to Kill Thread in C#?
How to kill a thread instantly in C#?

编辑:

似乎有一些混乱与方法我列在上面。

首先,当有人点击取消按钮,这个程序被调用:

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

接下来,当我去杀死一个线程,我宁愿没有永远等待线程停止。同时,如果线程仍处于活动状态,我不想让代码继续。所以,我使用了一个ManualResetEvent对象。它不应该需要一整秒(1000毫秒)只是为了停止线程,但每次WaitOne方法超时。

还在听的想法。

回答

7

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

进一步的阅读可见埃里克利珀的文章: Careful with that axe, part one: Should I specify a timeout?Careful with that axe, part two: What about exceptions?

编辑: 你怎么称呼的SQL Server? ADO,TDS,标准/定制库等...? 该呼叫应该作为异步。 因此:StartOpeningConnection,WaitFor OpeningComplete,StartQuery,WaitFor QueryComplete,Start CloseConnection,WaitFor CloseConnectionComplete等。在等待线程应该休眠的任何时候。在唤醒之后,检查你的父线程(UI线程)是否已经取消,或者发生了超时并退出线程并可能通知sqlserver你已完成(关闭连接)。

这并不容易,但很少是...

编辑2:在你的情况,如果你无法改变数据库代码asynchrone,使它成为一个独立的进程,杀掉,如果neccesary 。这样资源(连接等)将被释放。使用线程,情况并非如此。 但这是一个丑陋的破解

编辑3: 您应该使用BeginExecuteReader/EndExecuteReader模式。 this article is a good reference: 这将需要重写您的数据访问代码,但这是正确的做法。

0

当用户点击取消,您应该发出信号的事件(不能杀死线程)。在你的例子中,ManualResetEvent的“mre”的作用域应该在线程函数之外。

+0

我要编辑我的帖子。我想我已经写错了。 – jp2code 2011-02-17 21:21:15

+0

这里的观点(和MarcelDevG指出的一样)是你不要杀死一个线程。线程应该优雅地退出并自行清理。 – 2011-02-17 21:45:50

+0

这将是一个想法。但是,我无法告诉我们的SQL Server 2000停止查询。我想我可以简单地放弃线程(将其设置为NULL,然后在执行下一个查询时创建一个新实例),但我想知道如何停止线程。 – jp2code 2011-02-17 22:06:56

2

给我的感觉是,同时螺纹1000毫秒中止是不够的。 MSDN建议您调用Thread.Join。看到正在中止的代码肯定会有所帮助。

Thread.Abort

线程不能保证立即中止 ,或在所有。 如果一个线程执行 无限量的计算,则会发生这种情况 终止块被终止程序的部分 调用,因此 无限期地延迟中止。到 等到一个线程中止后, 可以在调用Abort方法后调用线程 上的Join方法,但 不能保证等待将会以 结束。

+0

好吧,它有很多自定义设计的对象被填充在查询中。查询轮询6个不同的数据表(我没有设计系统,我只是为它编写软件)。在查询每个表之前,我检查线程是否被中止。比赛条件,也许,但这就是我所拥有的。 – jp2code 2011-02-17 21:19:06

1

你传递给你的KillThread方法是什么?取消按钮将在UI线程上被点击,而不是你想要杀死的那个。