The same thread lock statement recursion of C # written test questions will not deadlock

Time:2021-3-6

A few days ago, when I was wandering on the Internet, I came across a question and its answer

According to the thread safety knowledge, this paper analyzes the following code, whether it will cause deadlock when I > 10 when calling the test method, and briefly explains the reasons.


public void test(int i) 
 { 
  lock(this) 
  { 
   if (i > 10) 
   { 
     i--; 
     test(i); 
   } 
  } 
 }

A: there will be no deadlock. (but there is a point that int is passed by value, so each change is only a copy, so there will be no deadlock. But if you change int to an object, deadlock will occur.)

When I see this question, I have only two answers in my mind. One is that deadlock will occur, and the other is that I won’t. ^_ ^I didn’t say it. I think the reason for deadlock is that the same thread can only enter the lock statement once. If the thread does not exit the lock statement, it cannot enter the lock statement again. The reason why deadlock does not occur is that the same thread can enter the lock statement multiple times.

I copied this code into vs to run, and found that it did not enter deadlock, so I wanted to find an authoritative reason to explain it. Finally, I found such a description in line 7 of the second edition of CLR via C # (Chinese version, Tsinghua University Press) on page 530: “it should also be noted that threads can recursively have synchronization blocks.”. That is, the same thread can call the lock statement recursively.

The above only discusses the case of single thread, and the following code shows the case of two threads:

using System;
using System.Threading;

namespace LockDemo
{
  class Program
  {
    static void Main(string[] args)
    {
      Program p = new Program();
      MyObj obj = new MyObj();
      //First thread
      Thread thread1 = new Thread(p.test);
      thread1.Name = "thread1";
      //First thread
      Thread thread2 = new Thread(p.test);
      thread2.Name = "thread2";
      //Start thread
      thread1.Start(obj);
      thread2.Start(obj);
      Console.Read();
    }

    public void test(object obj)
    {
      lock (this)
      {
        if (((MyObj)obj).value > 10)
        {
          ((MyObj)obj).value--;
          Console.Write(Thread.CurrentThread.Name + ":");
          Console.WriteLine(((MyObj)obj).value);
          Thread.Sleep(10);
          test(obj);
        }
        else
        {
          Console.WriteLine(Thread.CurrentThread.Name);
        }
      }
    }
  }
  /// <summary>
  ///Encapsulate a value type in a class to facilitate multiple thread calls
  /// </summary>
  public class MyObj
  {
    public int value;

    public MyObj()
    {
      //Assign the initial value to 20
      value = 20;
    }
  }
}

Here are the running results:

 

Because thread1 enters the lock statement first, the lock is always occupied by thread1 and recursively called until the condition is not satisfied. After thread1 releases the lock, when thread2 enters the lock statement, it is found that the recursion condition is no longer satisfied, that is, I < 10, so it exits directly.

What makes me feel strange is that the answer given on the Internet, that is, the text description in brackets, clearly indicates that the lock on this object in the code has nothing to do with the parameters passed? It’s strange to find a reason that int is passed by value to explain that there won’t be deadlock.

Note: if you don’t understand the technical principle behind lock, please refer to the book CLR via C #.

 

References: CLR via c#, Second Edition, P. 530, Tsinghua University Press

The above is the whole content of this article, I hope to help you learn, and I hope you can support developer more.