繁体   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