Ang*_*ker 16 .net c# multithreading .net-3.5
我不是想给打一个死 马,诚实.我已经阅读了有关线程查杀的所有建议,但请考虑代码.它执行以下操作:
StartThread方法)WAITFOR命令 - 这意味着它将一直坐在那里直到队列中有东西.这一切都在MonitorQueue方法中.杀死线程.我试过.Interrupt- 似乎什么也没做.然后我尝试了.Abort,永远不应该使用,但即使这样做也没有.
Thread thxMonitor = new Thread(MonitorQueue);
void StartThread() {
thxMonitor.Start();
}
void MonitorQueue(object obj) {
var conn = new SqlConnection(connString);
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandTimeout = 0; // forever and ever
cmd.CommandType = CommandType.Text;
cmd.CommandText = "WAITFOR (RECEIVE CONVERT(int, message_body) AS Message FROM SBQ)";
var dataTable = new DataTable();
var da = new SqlDataAdapter(command);
da.Fill(dataTable);
da.Dispose();
}
void KillThreadByAnyMeansNecessary() {
thxMonitor.Interrupt();
thxMonitor.Abort();
}
Run Code Online (Sandbox Code Playgroud)它真的可以杀死一个线程吗?
我讨厌不回答你的问题,但考虑以不同的方式解决这个问题.T-SQL允许使用WAITFOR指定TIMEOUT参数,这样如果在特定时间段内未收到消息,则该语句将退出并且必须再次尝试.你看这个了,并在在,你必须等待模式一次.权衡是你没有立即让线程在请求时死亡 - 你必须等待你的超时在你的线程死亡之前到期.
您希望这种情况发生得越快,您的超时间隔就越小.想要立即发生吗?然后你应该轮流投票.
static bool _quit = false;
Thread thxMonitor = new Thread(MonitorQueue);
void StartThread() {
thxMonitor.Start();
}
void MonitorQueue(object obj) {
var conn = new SqlConnection(connString);
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "WAITFOR (RECEIVE CONVERT(int, message_body) AS Message FROM SBQ) TIMEOUT 500";
var dataTable = new DataTable();
while(!quit && !dataTable.AsEnumerable().Any()) {
using (var da = new SqlDataAdapter(command)) {
da.Fill(dataTable);
}
}
}
void KillThreadByAnyMeansNecessary() {
_quit = true;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
虽然这可能像轮询队列一样,但事实并非如此.当你进行轮询时,你正在积极地检查某些东西,然后你正在等待避免一个"旋转"状态,你不断烧毁CPU(尽管有时你甚至不等).
考虑在检查条目时轮询方案中发生的情况,然后等待500毫秒.如果队列中没有任何内容,并且200ms后消息到达,则在轮询时必须再等待300ms才能获得消息.如果超时,如果消息到达"等待"方法的超时200ms,则会立即处理该消息.
当轮询在紧密循环中进行轮询与等待恒定的高CPU时,等待的时间延迟是轮询通常不能令人满意的原因.等待超时没有这样的缺点 - 唯一的权衡是你必须等待你的超时到期才能让你的线程死掉.
设置一个Abort标志来告诉线程需要终止.将伪记录附加到ServiceBroker队列.然后WAITFOR返回.然后线程检查其"Abort"标志,并找到它设置,从队列中删除虚拟记录并退出.
另一种变体是将"真正的"毒丸记录添加到ServiceBroker监控的表的规范中 - 非法记录号等.这样可以避免以任何直接方式触及线程 - 总是一件好事:)这可能会更复杂,特别是如果每个工作线程都被用来通知实际终止,但是如果工作线程仍然有效, ServiceBroker和DB都在不同的盒子上.我添加了这个作为编辑,因为,考虑到它的更多,它似乎更灵活,毕竟,如果线程通常只通过通信.DB,为什么不用DB关闭它们呢?没有Abort(),没有Interrupt(),并且希望没有生成锁定的Join().
不要这样做!严重地!
杀死线程所需调用的函数是函数TerminateThread,您可以通过 P/Invoke 调用该函数。关于为什么不应该使用此方法的所有原因都在文档中
TerminateThread 是一个危险的函数,只应在最极端的情况下使用。仅当您确切知道目标线程正在做什么,并且您控制了目标线程在终止时可能正在运行的所有代码时,才应调用 TerminateThread。例如,TerminateThread 可能会导致以下问题:
- 如果目标线程拥有临界区,则该临界区不会被释放。
- 如果目标线程正在从堆中分配内存,则堆锁不会被释放。
- 如果目标线程在终止时正在执行某些 kernel32 调用,则该线程进程的 kernel32 状态可能会不一致。
- 如果目标线程正在操作共享 DLL 的全局状态,则 DLL 的状态可能会被破坏,从而影响 DLL 的其他用户。
需要注意的重要一点是粗体部分,以及在 CLR / .Net 框架下您永远不会处于确切知道目标线程正在做什么的情况(除非您碰巧编写 CLR)。
澄清一下,在运行 .Net 代码的线程上调用 TerminateThread 很可能会使您的进程死锁,或者处于完全不可恢复的状态。
如果您找不到某种方法来中止连接,那么您最好让该线程在后台运行,而不是尝试使用TerminateThread. 其他人已经发布了关于如何实现这一目标的替代建议。
该Thread.Abort方法稍微安全一些,因为它会引发ThreadAbortException而不是立即拆除线程,但这有一个缺点,即并不总是有效 - 如果 CLR 实际上在该线程上运行代码,则 CLR 只能抛出异常,但在这种情况下该线程可能正在等待某些 IO 请求在本机 SQL Server 客户端代码中完成,这就是为什么您的调用Thread.Abort没有执行任何操作,并且在控制权返回到 CLR 之前不会执行任何操作。
Thread.Abort无论如何也有它自己的问题,并且通常被认为是一件坏事,但是它可能不会完全软管你的过程(尽管它仍然可能,取决于运行的代码正在做什么)。
| 归档时间: |
|
| 查看次数: |
33502 次 |
| 最近记录: |