C# 终止使用文件流的任务的正确方法是什么
我有一个并行任务,在文件中写入一些数据C# 终止使用文件流的任务的正确方法是什么,c#,file-io,task,cancellation,C#,File Io,Task,Cancellation,我有一个并行任务,在文件中写入一些数据 using (var lFileStream = File.Open(aDestinationFile, shouldResume ? FileMode.Append : FileMode.Create, FileAccess.Write)) { try { while ((lCount = lDownloadStream.Read(lBuf, 0, lBuf.Length)) > 0) {
using (var lFileStream = File.Open(aDestinationFile, shouldResume ? FileMode.Append : FileMode.Create, FileAccess.Write))
{
try
{
while ((lCount = lDownloadStream.Read(lBuf, 0, lBuf.Length)) > 0)
{
lFileStream.Write(lBuf, 0, lCount);
}
}
finally
{
lFileStream.Close();
}
}
我通过以下方式启动该任务:
Task.Factory.StartNew(() =>
{
try
{
myMethod();
}
catch (Exception ex)
{
Log.Exc(ex);
}
}
, _resetEvent.Token);
在某些情况下,我必须终止任务:
_resetEvent.Cancel(false);
try
{
_task.Dispose();
}
catch
{
}
任务停止后,我开始一项新任务,但当我尝试访问所使用的文件时,我得到:
进程无法访问文件“bla bla”,因为它正在使用中
通过另一个过程
如何才能正确地“终止”任务?当您将
取消令牌
传递给任务时,如果在任务计划程序开始启动任务时令牌被取消,那么所做的就是阻止任务启动。一旦任务已经启动,它对任务没有影响
您需要做的是“协作取消”,您需要检查在任务中运行的代码中的令牌,并让它取消正在执行的操作。最简单的方法是将CancelationToken传递给方法本身,然后运行函数ThrowIfCancellationRequested()程序将抛出一个操作canceledException
,并执行为处理该异常而设置的任何清理操作
private void myMethod(CancellationToken token)
{
using (var lFileStream = File.Open(aDestinationFile, shouldResume ? FileMode.Append : FileMode.Create, FileAccess.Write))
{
//The try-finally was not nessessary, Dispose() will call Close() for you.
while ((lCount = lDownloadStream.Read(lBuf, 0, lBuf.Length)) > 0)
{
token.ThrowIfCancellationRequested();
lFileStream.Write(lBuf, 0, lCount);
}
}
}
Task.Factory.StartNew(() =>
{
try
{
myMethod(_resetEvent.Token);
}
catch (Exception ex)
{
//If the task was canceled we don't need to log the exception.
if(!ex is OperationCanceledException)
Log.Exc(ex);
}
}
, _resetEvent.Token);
为了减少重构,可以对writer方法执行以下操作
//All your old code can still call this method.
public void myMethod()
{
myMethod(CancellationToken.None); //Call the overload with a empty token.
}
//New code that needs to cancel the operation can call this method.
public void myMethod(CancellationToken token)
{
//Slightly modified old Writer code that uses the CancelationToken inside any loops or in between any long running operations that can't be interrupted.
}
将
CancellationToken
传递到任务时,如果在任务计划程序开始启动任务时取消了令牌,那么所做的就是阻止任务启动。一旦任务已经启动,它对任务没有影响
您需要做的是“协作取消”,您需要检查在任务中运行的代码中的令牌,并让它取消正在执行的操作。最简单的方法是将CancelationToken传递给方法本身,然后运行函数ThrowIfCancellationRequested()程序将抛出一个操作canceledException
,并执行为处理该异常而设置的任何清理操作
private void myMethod(CancellationToken token)
{
using (var lFileStream = File.Open(aDestinationFile, shouldResume ? FileMode.Append : FileMode.Create, FileAccess.Write))
{
//The try-finally was not nessessary, Dispose() will call Close() for you.
while ((lCount = lDownloadStream.Read(lBuf, 0, lBuf.Length)) > 0)
{
token.ThrowIfCancellationRequested();
lFileStream.Write(lBuf, 0, lCount);
}
}
}
Task.Factory.StartNew(() =>
{
try
{
myMethod(_resetEvent.Token);
}
catch (Exception ex)
{
//If the task was canceled we don't need to log the exception.
if(!ex is OperationCanceledException)
Log.Exc(ex);
}
}
, _resetEvent.Token);
为了减少重构,可以对writer方法执行以下操作
//All your old code can still call this method.
public void myMethod()
{
myMethod(CancellationToken.None); //Call the overload with a empty token.
}
//New code that needs to cancel the operation can call this method.
public void myMethod(CancellationToken token)
{
//Slightly modified old Writer code that uses the CancelationToken inside any loops or in between any long running operations that can't be interrupted.
}
您不需要尝试使用block calls
Close()最终阻止从调用的Dispose()
给你。@ScottChamberlain纠正你说的:使用
不会调用Close
它会调用Dispose
,然后调用Close
@SriramSakthivel这就是我想说的(感谢你让它变得不那么复杂),你不需要尝试最终阻止Dispose()
从您的调用,使用
块调用Close()
。@ScottChamberlain纠正您所说的:使用
不会调用Close
它会调用Dispose
然后调用Close
@SriramSakthivel这正是我想说的(感谢您让它不那么复杂)我做对了吗“合作癌变”是唯一的方法?我提出这个问题,因为“writer”方法是我的解决方案中其他方法也使用的代码。这就是为什么我想避免重构是的,writer方法必须“配合”取消,否则必须等待写入完成,然后系统才会“关闭”。查看“我的更新”以简化重构,您只需修改writer函数和任何要支持的函数即可取消操作,writer函数的所有其他用途都可以保持不变。为什么要使用Task.Factory.StartNew
。您希望使用Stream.BeginWrite
和Stream.EndWrite
以及TaskFactory.fromsync
。如果您使用的是.NET 4.5或.NET 4.0,为了使它更具响应性,您可以让代码使用async/wait并替换无效流。Write(byte[],int,int)
调用任务流。WriteAsync(byte[],int,int,CancelationToken)
并将令牌传递给write函数。这将使您的函数在令牌发出后立即停止,而不是等待写入(
返回。@ScottChamberlainStream.WriteAsync
是4.5而不是4.0我是否正确了“合作cancalation”是唯一的方法?我问这个问题,因为“写入者”方法是我的解决方案中其他方法也使用的代码。这就是为什么我希望避免重构是的,writer方法必须“配合”取消,否则必须等待写入完成,然后才能“关闭”通过系统。请参阅我的更新以简化重构,您只需修改writer函数和任何支持取消操作的函数,writer函数的所有其他用途都可以保持不变。为什么要使用Task.Factory.StartNew
。您要使用Stream.BeginWrite
和e> Stream.EndWrite
与TaskFactory.fromsync
一起使用。如果您使用的是.NET 4.5或.NET 4.0,为了使其更具响应性,您可以让代码使用async/wait并替换无效的Stream.Write(byte[],int,int)
调用任务流.WriteAsync(byte[],int,int,CancelationToken)
并将令牌传递给写入函数。这将使您的函数在令牌发出后立即停止,而不是等待写入(
返回。@ScottChamberlainStream.WriteAsync
为4.5而非4.0