c# 锁没有按预期工作

c# lock not working as expected

这个 class 使用 lockInterlocked

increaseCount.with_lock.Run();increaseCount.with_interlock.Run(); 都在 96-100 之间打印。

我希望它们都打印 100。我做错了什么?

public static class increaseCount {
    public static int counter = 0;
    public static readonly object myLock = new object();
    public static class with_lock {
        public static void Run() {
            List<Thread> pool = new List<Thread>();
            for(int i = 0; i < 100; i++) {
                pool.Add(new Thread(f));
            }
            Parallel.ForEach(pool, x => x.Start());
            Console.WriteLine(counter); //should print 100
        }

        static void f() {
            lock(myLock) {
                counter++;
            }
        }
    }

    public static class with_interlock {
        public static void Run() {
            List<Thread> pool = new List<Thread>();
            for(int i = 0; i < 100; i++) {
                pool.Add(new Thread(f));
            }
            Parallel.ForEach(pool, x => x.Start());
            Console.WriteLine(counter);//should print 100
        }

        static void f() {
            Interlocked.Add(ref counter, 1);
        }
    }
}

在这两种情况下,您都启动线程但不等待它们完成,因此在打印结果和应用程序关闭之前不会达到 100。

如果在启动所有线程后您将等待所有这些线程完成 Thread.Join 您将始终得到正确的结果:

List<Thread> pool = new List<Thread>();
for (int i = 0; i < 100; i++)
{
    pool.Add(new Thread(f));
}

Parallel.ForEach(pool, x => x.Start());
foreach (var thread in pool)
{
    thread.Join();
}

Console.WriteLine(counter);

注意:这似乎是某种测试,但您应该知道在单个 lock 上阻塞多个线程是对资源的巨大浪费。

我相信这是因为您的 Parallel.Foreach 调用只是在 pool 中的所有线程上调用 start 但它们不一定在循环结束时完成并且 Console.WriteLine 是叫。如果您要在 Console.WriteLine 之前插入 Thread.Sleep(5000); // 5s sleep 或类似内容,它可能总是会打印出您期望的内容。

你的代码没问题。唯一的问题是你的期望。基本上,在显示计数器之前,并非所有 100 个线程都达到 运行。尝试在 Console.WriteLine(counter) 之前加上 Thread.Sleep(1000),你就会明白我的意思了。

编辑:第一次发错评论了。