c# 锁没有按预期工作
c# lock not working as expected
这个 class 使用 lock
和 Interlocked
。
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),你就会明白我的意思了。
编辑:第一次发错评论了。
这个 class 使用 lock
和 Interlocked
。
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),你就会明白我的意思了。
编辑:第一次发错评论了。