public void Read(string file)
{
_read ?? = new Thread(() => MethodA(file));
_read.Start();
}
private void CancelReading()
{
if (_read != null)
{
if (!_read.Join(100))
_read.Abort();
_read = null;
}
}
private void MethodA(string file)
{
try
{
Thread.Sleep(300);
MethodB(file);
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
ErrorMethod();
}
}
private void ErrorMethod()
{
CancelReading();
}
Here in this code, the line _read.Abort()
shows a warning about "Thread.Abort is obsolete". Is there any workaround or any alternatives for this?
I've tried one using CancellationToken, but couldn't resolve the issue. Here is the implementation using CancellationToken -
public void Read(string file)
{
CancelReading();
_cancellationTokenSource = new CancellationTokenSource();
_readTask = Task.Run(() => MethodA(file, _cancellationTokenSource.Token));
}
private void CancelReading()
{
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
_cancellationTokenSource = null;
}
}
private void MethodA(string file, CancellationToken cancellationToken)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
Thread.Sleep(300);
cancellationToken.ThrowIfCancellationRequested();
MethodB(file);
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
ErrorMethod();
}
}
private void ErrorMethod()
{
CancelReading();
}
Could anyone please help me to resolve this issue whether using CancellationToken or any other ways?
I've tried one using CancellationToken, but couldn't resolve the issue.
You need to forward the token to all "slow" operations. If you are doing IO operations, like reading from a file, you should be using the Async API, i.e.
private async Task<MyResult> MethodA(string file, CancellationToken cancel)
{
try
{
Task.Delay(300, cancellationToken);
await MethodB(file, cancel);
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
throw;
}
}
public async Task<MyResult> MethodB(string file, CancellationToken cancel){
var lines = await File.ReadAllLinesAsync(file, cancel);
foreach(var line in lines){
cancel.ThrowIfCancellationRequested();
// do processing
}
}
This way the task will be cancelled regardless if it is the waiting, the reading, or the processing that is slow.
Note that I rewrote the methods to be "pure", i.e. only using the input arguments and returning a result. This help reduce the risk of threading bugs.
Depending on how this is used you might be able to omit the Task.Run
-part. Keep in mind that when you use Tasks you should return Tasks all the way to the "edge" of the application, usually an event handler, like a button press or other UI event. You should also propagate exceptions so that the caller knows if the operation succeeded or not, and most likely catch OperationCancelledException
and other types of exceptions and handle each accordingly.
If the "slow" part is in a third party library without any support for cooperative cancellation the only real workaround is moving the library calls to a separate process, and use some form of RPC/IPC to communicate with this process. This way you can ask the OS to cleanly kill the process and reclaim all its resources.