Is It Considered Acceptable to Not Call Dispose() on a Tpl Task Object

Is it considered acceptable to not call Dispose() on a TPL Task object?

There is a discussion about this in the MSDN forums.

Stephen Toub, a member of the Microsoft pfx team has this to say:

Task.Dispose exists due to Task
potentially wrapping an event handle
used when waiting on the task to
complete, in the event the waiting
thread actually has to block (as
opposed to spinning or potentially
executing the task it's waiting on).
If all you're doing is using
continuations, that event handle will
never be allocated

...

it's likely better to rely on finalization to take care of things.

Update (Oct 2012)

Stephen Toub has posted a blog titled Do I need to dispose of Tasks? which gives some more detail, and explains the improvements in .Net 4.5.

In summary: You don't need to dispose of Task objects 99% of the time.

There are two main reasons to dispose an object: to free up unmanaged resources in a timely, deterministic way, and to avoid the cost of running the object's finalizer. Neither of these apply to Task most of the time:

  1. As of .Net 4.5, the only time a Task allocates the internal wait handle (the only unmanaged resource in the Task object) is when you explicitly use the IAsyncResult.AsyncWaitHandle of the Task, and
  2. The Task object itself doesn't have a finalizer; the handle is itself wrapped in an object with a finalizer, so unless it's allocated, there's no finalizer to run.

Do I need to dispose of a Task?

While the normal rule of thumb is to always call Dispose() on all IDisposable implementations, Task and Task<T> are often one case where it's better to let the finalizer take care of this.

The reason Task implements IDisposable is mainly due to an internal WaitHandle. This is required to allow task continuations to work properly, and only used when there is a continuation on a Task. If there is no continuation, the Task's Dispose method has no real effect - so in this case, it's not required.

That being said, in most cases where there is a Task continuation, it's often very, very difficult to write your code in a way that allows you to properly call Dispose(). Using statements typically do not work with Task instances, since the Task call is typically asynchronous in nature. It's very easy to dispose of the Task far too early, especially when using the using statement.

If, in your case, it's relatively simple to keep a reference to the Task and call Dispose() on it correctly, I would do so. However, if this is going to cause your logic to get much more complex, I would typically pretend that Task isn't IDisposable, and allow it to be cleaned up in the finalizer for the Task.

For more details, I'd recommend reading this thread on the MSDN forums where Stephen Toub describes why Task implements IDisposable in detail, and provides similar guidance to my suggestion above.

Should I dispose all disposable objects?

Yes, unless you're receiving it from a caller who needs it once you're done or has taken responsibility for calling Dispose(). The important thing is that someone calls Dispose() and if you are being passed an IDisposable instance, there needs to be an understanding ("contract") about whether you are taking ownership for it (and thus need to dispose it) or whether you are "borrowing it" and the caller will use/dispose it upon your return. These are the types of things good APIs have in their documentation.

If you are instantiating the object, make it easy on yourself to automatically dispose by using using.

How to dispose a Task as soon as possible

You do not have to dispose of the tasks in your situation. It only implements IDisposable because it may allocate a WaitHandle (which is disposable):

Internally, Task may allocate a WaitHandle which can be used to wait on the Task to complete. WaitHandle is IDisposable because it holds onto a SafeWaitHandle internally, which is IDisposable. SafeWaitHandle wraps a native handle resource: if the SafeWaitHandle isn’t disposed, eventually its finalizer will get around to cleaning up the wrapped handle, but in the meantime its resources won’t be cleaned up and pressure will be put on the system. By implementing IDisposable on Task, then, we enable developers concerned about aggressively cleaning up these resources to do so in a timely manner.

Now, Microsoft did realize this can create confusion so they made some changes and created some guidance:

We’ve made it much less likely that the Task’s WaitHandle will be allocated at all. We’ve re-implemented WaitAll and WaitAny so that they don’t rely on a Task’s WaitHandle, and we’ve avoided using it internally for any of the new Task or async/await-related functionality introduced in .NET 4.5. Thus, the only way the WaitHandle will be allocated is if you explicitly ask for the Task’s IAsyncResult.AsyncWaitHandle, and that should be quite rare. This means that except in such very infrequent circumstances, disposing of a Task is completely unnecessary.

and

We’ve made Tasks usable even after they’ve been disposed. You can now use all of the public members of Task even after its disposal, and they’ll behave just as they did before disposal. The only member you can’t use is IAsyncResult.AsyncWaitHandle, since that’s what actually gets disposed when you dispose of a Task instance; that property will continue to throw an ObjectDisposedException if you try to use it after the Task has been disposed. This means you should feel freely comfortable caching completed Tasks, knowing that they’re observationally pure. Additionally, moving forward, IAsyncResult usage should drop significantly now that we have async/await and the Task-based Async Pattern, and even for continued usage of IAsyncResult, usage of its AsyncWaitHandle is quite rare.

The basic advice however is:

“No. Don’t bother disposing of your tasks.” It’s often difficult to find a good place to do so, there’s almost never a reason to do so, and depending on your reference assemblies, you might not even be able to do so.

(source)

Will my c# 8.0 using declaration dispose my object correctly? When is it disposed?

using var clientWebSocket = new ClientWebSocket(); is just syntactical sugar, it's short hand for:

private async Task<bool> ConnectAsync(CancellationToken cancellationToken)
{
using( var clientWebSocket = new ClientWebSocket())
{
_clientWebSocket = clientWebSocket;

try
{
await clientWebSocket.ConnectAsync(new Uri(_url), cancellationToken);
}
catch
{
return false;
}

try
{
while (clientWebSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
{
var bytesReceived = new ArraySegment<byte>(new byte[1024]);
var receiveResult = await clientWebSocket.ReceiveAsync(bytesReceived, cancellationToken);
var message = Encoding.UTF8.GetString(bytesReceived.Array, 0, receiveResult.Count);

...
}
}
catch
{
return false;
}

try
{
if (clientWebSocket.State == WebSocketState.Open)
{
await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
}
}
catch
{
return false;
}

return true;

}
}

which is short hand for:

private async Task<bool> ConnectAsync(CancellationToken cancellationToken)
{
var clientWebSocket = new ClientWebSocket();
try
{
_clientWebSocket = clientWebSocket;

try
{
await clientWebSocket.ConnectAsync(new Uri(_url), cancellationToken);
}
catch
{
return false;
}

try
{
while (clientWebSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
{
var bytesReceived = new ArraySegment<byte>(new byte[1024]);
var receiveResult = await clientWebSocket.ReceiveAsync(bytesReceived, cancellationToken);
var message = Encoding.UTF8.GetString(bytesReceived.Array, 0, receiveResult.Count);

...
}
}
catch
{
return false;
}

try
{
if (clientWebSocket.State == WebSocketState.Open)
{
await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
}
}
catch
{
return false;
}

return true;

}
finally
{
if (clientWebSocket != null) {
((IDisposable)clientWebSocket).Dispose();
}
}
}

I think it's also worth highlighting this comment:

I'm more worried that you're disposing something that you've assigned
to the field _clientWebSocket

clientWebSocket is going to get disposed, but because you assign _clientWebSocket to this (_clientWebSocket = clientWebSocket;), the object that varibale is pointing at will get disposed as well! They are the same thing. They reference each other. I'd imagine this is not what you want to happen here, but it's hard to tell from the code you've shared.

How to dispose of an object that it created in a task?

From the comments

Q: with the exception of disposing the result do you do (or want to do) anything else with the result in the calling code

A: No I do not

The easiest way to do this is to have the CreateDisposableAsync method clean up its own resources before it returns and return Task instead of Task<IDisposable>. The existing calling code shown in the OP would not have to change.

// change the signature
async Task CreateDisposableAsync(){
// use using blocks for anything that needs to be disposed
// try/finally is also acceptable
using(var someDisposableInstance = new SomethingDisposable()){
// implementation
}
}

TPL: Dispose processed items

is this the expected behavior of TPL?

Yes. It doesn't root all the objects (they are available for garbage collection and finalization), but it does not dispose them, either.

and is there any option to set so the resources are released at the end of each iteration?

No.

how can I can make sure dispose is auto called when the last block/action executed on an input?

To dispose objects, your code should call Dispose. This is fairly easily done by modifying ProcessImage or wrapping it in a delegate.

If ProcessImage is synchronous:

var proImage = new TransformBlock<Image, double>(image => { using (image) return ProcessImage(image); });

or if it's asynchronous:

var proImage = new TransformBlock<Image, double>(async image => { using (image) return await ProcessImage(image); });


Related Topics



Leave a reply



Submit