patterncsharpMinor
Async Task implementation
Viewed 0 times
asyncimplementationtask
Problem
Beeing on .NET 3.5 i don't have access to the TPL. Yet i have become fed up of having to manage manually the logic behind delegate.BeginInvoke type of scenarios each time and i set up to implement my own Task class.
Functionality it should support:
a thread pool thread)
This is my implementation. Can you guys please review it and specify if there are any issues i might not have considered or maybe more effective ways to implement some things?
```
public class Task
{
#region Members
private IAsyncResult _async;
private Func _action;
private Func _innerAction;
private WaitHandle _waitHandle;
private Thread _thread;
private object _completedLock = new object();
private object _abortLock = new object();
private T _result;
private bool _endCalled = false;
#endregion
#region Properties
public object Tag { get; private set; }
public bool IsCompleted { get; private set; }
public bool IsRunning { get; private set; }
public T Result
{
get
{
if (!_endCalled)
{
lock (_completedLock)
{
if (!_endCalled)
{
try
{
if (_async != null)
{
_result = _innerAction.EndInvoke(_async);
IsCompleted = true;
}
}
finally
{
_endCalled = true;
}
}
}
}
return _result;
}
}
#endregion
#region Events
public event EventHandler Completed;
Functionality it should support:
- starting a parallel execution (using
a thread pool thread)
- capable of Waiting on the result with a specific timeout
- capable of aborting said execution
- should provide event for callbacks to attach to
This is my implementation. Can you guys please review it and specify if there are any issues i might not have considered or maybe more effective ways to implement some things?
```
public class Task
{
#region Members
private IAsyncResult _async;
private Func _action;
private Func _innerAction;
private WaitHandle _waitHandle;
private Thread _thread;
private object _completedLock = new object();
private object _abortLock = new object();
private T _result;
private bool _endCalled = false;
#endregion
#region Properties
public object Tag { get; private set; }
public bool IsCompleted { get; private set; }
public bool IsRunning { get; private set; }
public T Result
{
get
{
if (!_endCalled)
{
lock (_completedLock)
{
if (!_endCalled)
{
try
{
if (_async != null)
{
_result = _innerAction.EndInvoke(_async);
IsCompleted = true;
}
}
finally
{
_endCalled = true;
}
}
}
}
return _result;
}
}
#endregion
#region Events
public event EventHandler Completed;
Solution
-
You may want to consider replacing the flags (
-
Some state checks use
Yeah, a few moons would need to be in alignment for this to happen ... but still.
-
If
-
Abort will not terminate the thread immediately, you should wait for it to complete before resetting the state.
-
I'm not sure aborting a thread pool thread is a good idea.
-
You set Tag in one of the constructors, but I don't see it being used anywhere.
You may want to consider replacing the flags (
IsRunning/IsCompleted) with a single state enum.-
Some state checks use
_abortLock while others use _completedLock.- If
Abort()is called on a Task that has not started,
- a context switch happens just before
ResetState()is called,
- a second thread calls
Run()and the new inner thread starts,
- another context switch happens and the first thread resumes to call
ResetState()
Yeah, a few moons would need to be in alignment for this to happen ... but still.
-
If
Run() is called followed by Abort() before the inner thread actually starts, then _thread could be null resulting the thread not actually being aborted and inconsistent state. (again with the moons.)-
Abort will not terminate the thread immediately, you should wait for it to complete before resetting the state.
-
I'm not sure aborting a thread pool thread is a good idea.
-
You set Tag in one of the constructors, but I don't see it being used anywhere.
Context
StackExchange Code Review Q#2346, answer score: 6
Revisions (0)
No revisions yet.