Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it OK to call Task.Run inside using statement?

Code like this, I want to put most of the work in a Task.Run, but I am not sure if the using statement will still work as expected.

using(MemoryStream ms = new MemoryStream())
{
    Task.Run(() => 
    { 
         /* capture ms and process the stream */ 
    }
}  // Will ms will be disposed here automatically?

Thanks.

like image 360
codewarrior Avatar asked Nov 15 '16 22:11

codewarrior


3 Answers

No - The stream disposal may run before your Task has finished running. You'd be better off putting the using inside the Task if you can, or manually handling the disposal at the end of the Task.

var ms = new MemoryStream();
Task.Run(() =>
{
    /* capture ms and process the stream */

    // Dispose of the stream manually when you are done
    ms.Dispose();
}

Note that if you are using the memory stream outside of the Task, then you run the risk of using it after it is disposed. If you can, only use the stream inside the Task and save the results to somewhere else.

Task.Run(() =>
{
    using(var ms = new MemoryStream())
    {
        /* capture ms and process the stream */
    }
}
like image 57
Jamie Penney Avatar answered Sep 20 '22 00:09

Jamie Penney


The stream will most likely be closed and disposed of before the task has completed. This following throws a ObjectDisposedException:

using(MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes("abc"),0,3))
{
    Task.Run(() => 
    { 
         Thread.Sleep(100);
         ms.Read(new byte[3], 0, 3);
    });
}

you could move the using statement into the task closure or you can await the task like:

using(MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes("abc"),0,3))
{
    await Task.Run(() => 
    { 
         Thread.Sleep(100);
         var bytes = new byte[3];
         ms.Read(bytes, 0, 3);
         Console.WriteLine(Encoding.ASCII.GetString(bytes));
    });
}
like image 33
Letseatlunch Avatar answered Sep 20 '22 00:09

Letseatlunch


In addition to the two variations above, how about using ContinueWith to dispose? This is especially useful when you pass the task implementation as a delegate rather than implementing it inline:

var ms = new MemoryStream();
Task.Run(TaskUsingMemoryStream).ContinueWith(task => ms.Dispose());

You could argue, why would you create the memory stream outside the task if you are then immediately disposing of it once the task finishes but given that is what the OP is doing I assume there is some logic to this in their bigger picture. It think all answers have queried this choice.

like image 27
CodingLumis Avatar answered Sep 19 '22 00:09

CodingLumis