为什么要“锁定”阻止不起作用?

发布于 2024-12-03 13:13:43 字数 1044 浏览 2 评论 0原文

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();

有时会打印“99”,有时会打印“100”,无论 lock{...} 块是否存在。我的代码有什么错误吗?

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++;
        }
    }
}

This code is in a console application:

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();

Sometime it prints '99' and sometime '100', regardless of whether the lock{...} block exists or not. Is there any wrong in my code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

铁轨上的流浪者 2024-12-10 13:13:43

这里的问题是,您正在启动线程,并且在调用将输出写入控制台时它们尚未完全完成。

循环从i个线程开始,我们将它们想象为蜜蜂将收集作为工作,并不是所有的都去同一个食物源,所以有些比其他的需要更长的时间返回;然后,回到蜂巢,我们突然说:“嘿,蜜蜂,我需要统计人数!”,“...1、2、3...,只有三个?”不,一些i-3仍在外面搜寻!

因此,我们的想法是,我们必须有一个工作何时完成的指示器,或者某种归巢信号,让所有蜜蜂返回蜂巢进行人数统计。这可以通过 加入 来完成,或手动状态检查(这本质上是让你坚持到最后一个旅居者返回。)

The problem here would be that you're kicking off the threads and they're not entirely finished by the time of your call to write output to the console.

The loop starts off i threads, we'll imagine these as bees going of collecting as work, not all going to the same food source so some take longer to return than others; then, back at the hive, we suddenly say: "Hey, bees, I need a headcount!", "...1, 2, 3..., only three?" No, some i-3 are still scrounging around outside!

So, the idea is that we must have an indicator of when work is completed, or a homing signal of sorts to get all bees back to the hive for the headcount. This can be done with Join, or manual state checking (which essentially has you holding out until the last sojourner returns.)

唱一曲作罢 2024-12-10 13:13:43

您不是在等待线程完成。在输出计数之前有多少人完成了工作完全取决于运气。

添加,您始终会得到 100

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

        }

WriteLine 之前

You're not waiting for the threads to finish. It'e entirely a matter of luck how many have done their work before you output the count.

Add

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

        }

before the WriteLine, and you always get 100.

始终不够爱げ你 2024-12-10 13:13:43

你应该保护你的 getter public int Count { get { return m_count; } } 带有锁,否则线程 B 可能正在读取该值,而另一个线程 A 正在 Add 方法中更新计数,这可能会导致您获得不一致的数据视图。

You should protect your getter public int Count { get { return m_count; } } with a lock to, else a thread B could be reading that value, while another thread A is updating count in your Add method, this can cause you to get an inconsistent view of your data.

想念有你 2024-12-10 13:13:43

当您调用 Count 时,它不是确定性的。它可能发生在任何线程完成之前,或者所有线程完成之后,甚至在中间的某个地方。如果你想等到所有线程都完成,你应该加入它们。

It is not deterministic when your call to Count happens. It may happen before any thread has finished, or after all threads have finished or even somewhere in the middle. If you want to wait until all thread have finished, you should join them.

猛虎独行 2024-12-10 13:13:43

这是一个经典的竞赛条件,我认为你到时候能达到接近 100 就很幸运了您的 Console.WriteLine 被调用。

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 或类似于做一些同步。

It's a classic race condition, and I consider you lucky to get anywhere near 100 by the time your Console.WriteLine is invoked.

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);

Consider using a CountdownEvent or similar to do a bit of synchronization.

柠北森屋 2024-12-10 13:13:43

不确定这是否是您正在寻找的答案,但要以线程安全的方式增加计数器,您应该使用 Interlocked.Increment 文档

Not sure that this is the answer you're looking for, but to incrememnt a counter in a threadsafe way you should use Interlocked.Increment docs

再见回来 2024-12-10 13:13:43

当您打印计数时,您不知道线程是否已完成。代码中的“正确”输出可以是 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;

When you print the count you have no idea of whether or not the threads have completed or not. A "correct" output in your code could be any number between 0 and 100.

To be certain to get 100 as output, you mustn't get the value of Count until all threads have completed. You can do that by calling Thread.Join on all threads or (even better) use something like Parallel.For to start the threads:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文