Search code examples
.netlockingtaskscheduled-tasks

What could happen if we lock(TaskInstance) not shared?


An example:

try
{
    var myTask = Task.Run(async () =>
    {
        await Task.Delay(1);
    });
    
    myTask.ContinueWith(myContinuedTask =>
    {
        lock (myTask)
        {
            Task.Delay(1).Wait();
            Console.WriteLine(myContinuedTask.Id);
        }
    });
}
catch (Exception ex)
{
    Console.WriteLine(ex.ToString());
}
  1. When myContinuedTask lock myTask, it's like making lock(this), right?

  2. This is not a good idea if the instance is used outside the control of this code, right?

  3. If this instance is only used inside the control of this code, is it possible that myContinuedTask will Never get the lock and, thus, will stay in a waiting state?

I know that tasks are managed by a TaskScheduler. And I don't know if this one is making some lock on the task instances which could possibly lead to a dead lock? (i need more info)

  1. The Id field of a Task is not guaranteed to be unique. It's an int, so 4^32 max tasks can exists, right ? This seems really low. Is it per process, per thread, per session?

Solution

  • 1) When myContinuedTask lock myTask, it's like making lock(this), right ?

    No; it's the same as lock(myContinuedTask).

    2) This is not a good idea if the instance is used outside the control of this code, right ?

    Correct. You want to always lock on private or local scope variables whenever possible. In addition, I recommend having a separate object that is only used as a lock and nothing else.

    3) If this instance is only used inside the control of this code, is it possible that myContinuedTask will Never get the lock and, thus, will stay in a waiting state ? I know that tasks are managed by a TaskScheduler. And I don't know if this one is making some lock on the task instances which could possibly lead to a dead lock ?? (i need more info)

    Sure, it's possible. As soon as you expose an object instance that you use for locking, you encounter the possibility of deadlocks.

    4) The Id field of a Task is not guarented to be unique. It's an int, so 4^32 max tasks can exists, right ? This seems really low. Is it per process, per thread, per session, ... ?

    They just start duplicating, that's all. No worries.


    Other problems with the code include:

    • Using ContinueWith instead of await.
    • Using Task.Delay(..).Wait() instead of Thread.Sleep.

    Also, since this is asynchronous code, you may want to consider using SemaphoreSlim instead of lock.