So, I'm creating a download manager, and I've designed every bit specifically so that it can be shut down at any second without giving it the time to clean up. However, I can't seem to find a way to kill my downloader threads. I tried using Thread.Abort (actually, that's my way of giving them time to clean up: they catch the ThreadAbortException and handle it themselves), but as you can already guess, it's no good. I'd use a flag or something, but when a thread is waiting for a network operation to complete, it's pretty much blocked completely. Any ideas on how to at least interrupt the network operation so I can shut down without waiting a noticeable amount of time?
所以,我正在创建一个下载管理器,并且我已经专门设计了每一个位,以便它可以在任何时候关闭,而无需花时间进行清理。但是,我似乎无法找到杀死我的下载程序线程的方法。我尝试使用Thread.Abort(实际上,这是我给他们时间清理的方式:他们捕获ThreadAbortException并自己处理它),但正如你已经可以猜到的那样,这并不好。我会使用标志或其他东西,但是当一个线程正在等待网络操作完成时,它几乎完全被阻止了。关于如何至少中断网络操作的任何想法,以便我可以在不等待显着时间的情况下关闭?
Here's the relevant piece of code:
这是相关的代码:
try
{
Request.AddRange(StartPosition, EndPosition);
Owner.SetDefaultRequestParameters(Request);
Response = Request.GetResponse() as HttpWebResponse;
ResponseStream = Response.GetResponseStream();
var Buffer = new Byte[Downloader.BUFFER_SIZE];
while (true)
{
Paused.Wait();
if (bStopRequested)
break;
int Count = ResponseStream.Read(Buffer, 0, Buffer.Length); //gets stuck here
if (Count == 0)
break;
MemoryStream.Write(Buffer, 0, Count);
Downloaded += Count;
CurrentStreak += Count;
if (StartPosition + Downloaded >= EndPosition)
break;
if (MemoryStream.Capacity - CurrentStreak < Buffer.Length)
{
Owner.WriteToFile(MemoryStream, StartPosition + Downloaded - CurrentStreak, CurrentStreak);
MemoryStream.Seek(0, SeekOrigin.Begin);
CurrentStreak = 0;
}
}
}
catch (ThreadAbortException)
{
try
{
Response.Close();
}
catch { }
return; //fastest way I have found to shut the thread down, yet
}
EDIT: So, here's how I did it:
编辑:那么,我就是这样做的:
if (Request != null)
Request.Abort();
if (Response != null)
Response.Close();
ExecutionThread.Abort();
With this, no matter where the thread is stuck (getting a response or reading from the response stream) it will get cancelled and stop immediately.
有了这个,无论线程卡在哪里(从响应流中获得响应或读取),它都会被取消并立即停止。
2 个解决方案
#1
2
You could Dispose the ResponseStream
and then catch an ObjectDisposedException
.
您可以Dispose ResponseStream然后捕获ObjectDisposedException。
While this may work i suggest you design your application using CancellationToken to allow it to gracefully close instead of abruptedly aborting threads. You also might consider using async-await
to make your application more scalable and non-blocking.
虽然这可能有用,但我建议您使用CancellationToken设计应用程序以允许它优雅地关闭而不是中断中止线程。您还可以考虑使用async-await来使您的应用程序更具可伸缩性和非阻塞性。
#2
1
Not sure what the underlying socket does but if all fails you can directly bind to a socket in non blocking mode und use the Socket.BeginReceive method which will call your call back when data has arrived. If you do want to cancel the current operation you can call close simply the socket and thats it. See MSDN
不确定底层套接字的作用但是如果全部失败,你可以直接绑定到非阻塞模式的套接字,并使用Socket.BeginReceive方法,该方法将在数据到达时调用您的回调。如果你想取消当前的操作,你可以简单地调用关闭套接字就可以了。请参阅MSDN
The asynchronous BeginReceive operation must be completed by calling the EndReceive method. Typically, the method is invoked by the callback delegate.
必须通过调用EndReceive方法来完成异步BeginReceive操作。通常,该方法由回调委托调用。
This method does not block until the operation is complete. To block until the operation is complete, use one of the Receive method overloads.
在操作完成之前,此方法不会阻止。要阻止操作完成,请使用Receive方法重载之一。
To cancel a pending BeginReceive, call the Close method.
要取消挂起的BeginReceive,请调用Close方法。
You should check if you can get your hands on the underlying socket and try to close it.
您应该检查是否可以将手放在底层插座上并尝试关闭它。
#1
2
You could Dispose the ResponseStream
and then catch an ObjectDisposedException
.
您可以Dispose ResponseStream然后捕获ObjectDisposedException。
While this may work i suggest you design your application using CancellationToken to allow it to gracefully close instead of abruptedly aborting threads. You also might consider using async-await
to make your application more scalable and non-blocking.
虽然这可能有用,但我建议您使用CancellationToken设计应用程序以允许它优雅地关闭而不是中断中止线程。您还可以考虑使用async-await来使您的应用程序更具可伸缩性和非阻塞性。
#2
1
Not sure what the underlying socket does but if all fails you can directly bind to a socket in non blocking mode und use the Socket.BeginReceive method which will call your call back when data has arrived. If you do want to cancel the current operation you can call close simply the socket and thats it. See MSDN
不确定底层套接字的作用但是如果全部失败,你可以直接绑定到非阻塞模式的套接字,并使用Socket.BeginReceive方法,该方法将在数据到达时调用您的回调。如果你想取消当前的操作,你可以简单地调用关闭套接字就可以了。请参阅MSDN
The asynchronous BeginReceive operation must be completed by calling the EndReceive method. Typically, the method is invoked by the callback delegate.
必须通过调用EndReceive方法来完成异步BeginReceive操作。通常,该方法由回调委托调用。
This method does not block until the operation is complete. To block until the operation is complete, use one of the Receive method overloads.
在操作完成之前,此方法不会阻止。要阻止操作完成,请使用Receive方法重载之一。
To cancel a pending BeginReceive, call the Close method.
要取消挂起的BeginReceive,请调用Close方法。
You should check if you can get your hands on the underlying socket and try to close it.
您应该检查是否可以将手放在底层插座上并尝试关闭它。