簡體   English   中英

c# .net 4.8 winforms。 鎖 object 可以在簡單的單線程應用程序中同時鎖定多次

[英]c# .net 4.8 winforms. Lock object can be locked several times simultaneously in simple single thread app

重復的問題。 在這里回答...

鎖定 aqcuired 並且進一步嘗試鎖定不會阻塞:C# 鎖定是否可重入?

基本上(從上面的鏈接復制):

.NET 中的鎖是可重入的。 只有來自其他線程的獲取被阻塞。 當同一個線程多次鎖定同一個 object 時,它只是增加一個計數器,並在釋放時減少它。 當計數器達到零時,實際上釋放鎖以供其他線程訪問。


c# .net 4.8 winforms。 一個按鈕,一個多行文本框。

簡單的應用程序 - 單擊按鈕,它等待 2 秒(doevents 2 秒),它會寫出。

我按了 6 次按鈕,大約相隔一秒。 我知道 doevents 允許拾取更多點擊事件。 我可以看到,在處理完成之前的單擊之前,鎖沒有等待,並且事件以相反的順序完成。

Q1 - 為什么鎖不上鎖?

Q2 - 為什么點擊事件以相反的順序完成?

Q3 - 這里實際發生了什么?

using System.Windows.Forms;

namespace WindowsFormsApplication_testlock
{
    public partial class Form1 : Form
    {
        object _objLock;
        int _intIteration;
        System.Collections.Generic.Dictionary<int, DateTime> _lstIterationsTimes;
        public Form1()
        {
            InitializeComponent();


            _objLock = new object();
            _intIteration = 0;
            _lstIterationsTimes = new Dictionary<int, DateTime>();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            _intIteration++;
            _lstIterationsTimes.Add(_intIteration, DateTime.Now);
            Process(_intIteration);
        }

        private void Process(int intIteration)
        {
            textBox1.Text += "About to lock - " + intIteration.ToString() + Environment.NewLine;
            lock (_objLock)
            {
                textBox1.Text += "Succeeded to lock - " + intIteration.ToString() + Environment.NewLine;
                

                while ( (DateTime.Now - _lstIterationsTimes[intIteration]).TotalSeconds < 2)
                {
                    Application.DoEvents();
                }
                textBox1.Text += "About to unlock - " + intIteration.ToString() + Environment.NewLine ;
            }

            
        }
    }
}

Output:

即將鎖定 - 1

成功鎖定 - 1

即將鎖定 - 2

成功鎖定 - 2

即將鎖定 - 3

成功鎖定 - 3

即將鎖定 - 4

成功鎖定 - 4

即將鎖定 - 5

成功鎖定 - 5

即將鎖定 - 6

成功鎖定 - 6

即將解鎖 - 6

即將解鎖 - 5

即將解鎖 - 4

即將解鎖 - 3

即將解鎖 - 2

即將解鎖 - 1

Q1 - 為什么鎖不上鎖?

當您按下 button1 時,對button1_Click的調用總是在同一個線程上,即 GUI 線程上。 在 C# 中,一個線程可能多次進入同一個鎖。

Q2 - 為什么點擊事件以相反的順序完成?

Q3 - 這里實際發生了什么?

見下文。


正在發生的事情以及原因可以總結在下圖中(為令人震驚的質量道歉 - 我在 PowerPoint 中做了這個) - 為了簡單起見,我將調用Process方法的次數限制為 3:

發生的事情如下 - 所有都在 GUI 線程上:

  • button1_Click被觸發,它將_intIteration增加到1然后調用Process(1)
  • 內部Process(1)
    • 由於鎖中沒有其他線程,因此立即進入鎖。
    • while循環中,允許應用程序通過重復調用DoEvents()來等待用戶的輸入。
    • while循環期間的某個時刻,再次單擊 button1。 button1_Click返回之前, DoEvents()調用不會返回。
    • button1_Click被觸發,它將_intIteration增加到2然后調用Process(2)
    • Process(2)內部(仍在 GUI 線程上):
      • 由於鎖中沒有其他線程,因此立即進入鎖 - 該線程已經進入鎖一次,但單個線程可以多次重新進入同一個鎖。
      • while循環中,允許應用程序通過重復調用DoEvents()來等待用戶的輸入。
      • while循環期間的某個時刻,再次單擊 button1。 button1_Click返回之前, DoEvents()調用不會返回。
      • button1_Click被觸發,它將_intIteration增加到3然后調用Process(3)
      • Process(3)內部(仍在 GUI 線程上):
        • 由於鎖中沒有其他線程,因此立即進入鎖 - 該線程已經兩次進入鎖,但單個線程可以多次重新進入同一個鎖。
        • while循環中,允許應用程序通過重復調用DoEvents()來等待用戶的輸入。
        • 沒有發生用戶交互,因此Process(3)在打印“About to unlock - 3”后返回
      • button1_Click的第三級作為Process(3)返回。
      • DoEvents() (從Process(2)調用)返回,因此執行返回到Process(2)
    • Process(2)在打印“About to unlock - 2”后返回
    • button1_Click的第二級作為Process(2)返回。
  • DoEvents() (從Process(1)調用)返回,因此執行返回到Process(1)
  • Process(1)在打印“About to unlock - 1”后返回
  • button1_Click的第一級返回為Process(1)返回。

請注意,一旦停止單擊 button1 並且退出while循環, DoEvents()方法中有多個堆棧幀。 這些方法必須以后進先出的順序退出,這就是Process(3)退出然后Process(2)退出然后Process(1)退出的原因,導致

About to unlock - 3

About to unlock - 2

About to unlock - 1

你不確定。


由於這一切都發生在一個線程上,因此查看以下代碼可能更容易,該代碼向您展示了正在發生的事情:

private static object _objLock = new object();

public static void Main(params string[] arguments)
{
    Recurse(1);
}

public static void Recurse(int iteration)
{
    if ( iteration > 3 )
        return;

    Console.WriteLine($"About to lock - {iteration}");

    lock ( _objLock )
    {
        Console.WriteLine($"Entered lock - {iteration}");

        Recurse(iteration + 1);

        Console.WriteLine($"Releasing lock - {iteration}");
    }
}

將其寫入控制台:

About to lock - 1
Entered lock - 1
About to lock - 2
Entered lock - 2
About to lock - 3
Entered lock - 3
Releasing lock - 3
Releasing lock - 2
Releasing lock - 1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM