簡體   English   中英

為什么“鎖定”塊不起作用?

[英]Why “lock” block not work?

public class ThreadInteroperateWithLock
{
    private int m_count;
    private object m_synLock;
    public ThreadInteroperateWithLock() 
    {
        m_count = 0;
        m_synLock = new object();
    }

    public int Count { get { return m_count; } }

    public void Add() 
    {
        //just simulate some work
        int temp=0;
        for (int i = 0; i < 10000; i++)
        {
            temp++;
        }

        //really job
        lock (m_synLock)
        {
            m_count++;
        }
    }
}

此代碼位於控制台應用程序中:

ThreadInteroperateWithLock ope = new ThreadInteroperateWithLock();
Thread[] threadArray = new Thread[100];
for (int i = 0; i < 100; i++)
{
    Thread thread = new Thread(new ThreadStart(ope.Add));
    thread.IsBackground = false;
    threadArray[i] = thread;
}
for (int i = 0; i < 100; i++)
{
    threadArray[i].Start();
}
Console.WriteLine(ope.Count);
Console.ReadKey();

無論lock{...}塊是否存在,有時它會打印'99'而有時'100'。 我的代碼有什么問題嗎?

這里的問題是你正在開始攻擊線程,並且在調用輸出到控制台的時候它們並沒有完全完成。

循環開始我的線程,我們會想象這些蜜蜂作為工作收集,而不是所有去往相同的食物來源,所以有些人需要更長的時間返回; 然后,回到蜂巢,我們突然說:“嘿,蜜蜂,我需要一個人數!”,“...... 1,2,3 ......,只有三個?” 不,有些i-3仍然在外面徘徊!

因此,我們的想法是,我們必須有一個工作完成時間的指示,或者各種歸巢信號,以便讓所有蜜蜂回到蜂巢的人數。 這可以通過Join或手動狀態檢查來完成(基本上你可以堅持到最后一個旅行者返回。)

你不是在等待線程完成。 在輸出計數之前,有多少人完成了他們的工作,這完全是一個幸運的問題。

        for (int i = 0; i < 100; i++)
        {
            threadArray[i].Join();

        }

WriteLine之前,你總是得到100

你應該保護你的getter public int Count { get { return m_count; } } public int Count { get { return m_count; } }配鎖,否則線程B可以被讀取值,而另一個線程A在您的Add方法更新計數,這可以使你得到你的數據不一致的看法。

這是一個經典的競爭條件 ,我認為在調用Console.WriteLine時,你可以幸運地接近100。

for (int i = 0; i < 100; i++)
{
    threadArray[i].Start();
}
//absolutely no guarantee that **ANY** threads have completed before next line
Console.WriteLine(ope.Count);

考慮使用CountdownEvent或類似方法進行一些同步。

你對Count的調用發生時,這不是確定性的。 它可能發生在任何線程完成之前,或者在所有線程完成之后,甚至在中間的某個地方。 如果你想等到所有線程都完成,你應該加入它們。

不確定這是你正在尋找的答案,但要以線程安全的方式增加計數器,你應該使用Interlocked.Increment docs

打印計數時,您不知道線程是否已完成。 代碼中的“正確”輸出可以是0到100之間的任何數字。

要確保獲得100作為輸出,在完成所有線程之前,不得獲得Count的值。 你可以通過在所有線程上調用Thread.Join或者甚至更好地使用Parallel.For來啟動線程:

Parallel.For(0, 100, idx => ope.Add);
// When we reach this line, we know all threads have completed so we can 
// safely get the count
var count = ope.Count;

暫無
暫無

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

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