C#线程问题为什么这里有无限循环
本文关键字:无限循环 这里 为什么 线程 问题 | 更新日期: 2023-09-27 17:57:49
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ThreadExample
{
public class Info
{
public int Counter;
private static object _lock = new object();
private List<Thread> ThreadList;
public Info(int counter)
{
Counter = counter;
ThreadList = new List<Thread>();
ThreadList.Add(new Thread(ThreadBody));
ThreadList.Add(new Thread(ThreadBody));
ThreadList[0].Name = "t1";
ThreadList[1].Name = "t2";
}
public void Start()
{
ThreadList.ForEach(t => t.Start(t.Name));
}
public void ThreadBody(object name)
{
while (Counter != 20)
{
lock (_lock)
{
Counter++;
Console.WriteLine("Thread {0} : the value of the counter is {1}", name.ToString(), Counter);
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ThreadExample
{
class Program
{
static void Main(string[] args)
{
Info info = new Info(0);
info.Start();
}
}
}
如果锁只是锁计数器++锁定(_lock({计数器++;}我没有无限循环,但如果锁像示例中那样,它会运行无限循环
可能是当Counter
达到19时,两个线程都进入循环,在再次测试值之前,循环最终会增加到21。
在读取Counter
的值时,您需要持有锁。对Counter
进行双重检查可能就足够了(在保持锁的同时,在while
循环内再次读取(。然而,我对此并不确定,因为我的大脑无法跟踪本机、之间各种线程内存模型的所有细节。NET、Java等等。即使在。NET中,ECMA模型显然与MS为其CLR所保证的不同(请参阅http://msdn.microsoft.com/en-us/magazine/cc163715.aspx和http://www.bluebytesoftware.com/blog/PermaLink,guid,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx(。有关双重检查可能起作用或不起作用的更多详细信息,请搜索"双重检查锁定"-显然应该很简单的事情背后有很多复杂性。
例如,以下是在我的机器上运行的片段:
Thread t1 : the value of the counter is 1
Thread t2 : the value of the counter is 2
Thread t2 : the value of the counter is 3
Thread t2 : the value of the counter is 4
Thread t2 : the value of the counter is 5
Thread t2 : the value of the counter is 6
Thread t2 : the value of the counter is 7
Thread t2 : the value of the counter is 8
Thread t2 : the value of the counter is 9
Thread t2 : the value of the counter is 10
Thread t2 : the value of the counter is 11
Thread t2 : the value of the counter is 12
Thread t2 : the value of the counter is 13
Thread t2 : the value of the counter is 14
Thread t2 : the value of the counter is 15
Thread t2 : the value of the counter is 16
Thread t2 : the value of the counter is 17
Thread t2 : the value of the counter is 18
Thread t2 : the value of the counter is 19
Thread t2 : the value of the counter is 20
Thread t1 : the value of the counter is 21
Thread t1 : the value of the counter is 22
... Thread t1 never stops ...
您会注意到,一旦Counter
变为20,t2
就会停止,但t1
不会注意到这一点。它已经进入循环(或决定进入循环(,认为Counter
是1(或可能是2或其他什么——只是不是20(。
这里的问题是您的线路:
while (Counter != 20)
由于您锁定了计数器的增量,在某个时刻,Counter
可以等于19。两个线程都可以进行检查,然后在内部递增计数器,使其在线程再次检查之前为21。
也就是说,即使两个线程没有同时达到20,一个线程也可能看到20并停止,而另一个线程在达到时的值为21,循环将永远继续。
顺便说一句,你的"修复"(只锁定增量(并不能真正修复它——它只会降低出错的可能性。原因是Console.WriteLine
调用要慢得多,所以更多的处理时间发生在锁中,这使得线程更有可能在再次看到条件检查之前通过条件检查。然而,只要锁定计数器增量,这种情况仍然可能发生(尽管这种情况更为罕见。(
你可以通过一个更灵活的条件来很容易地纠正这一点,比如:
while (Counter < 20)
这将导致线程在达到20或更高时立即退出。
根据代码的编写方式,两个线程都可以在计算各自的while
子句之前递增Counter
。在这种情况下,Counter
可以在命中下一个while
之前从19
变为21
。
试着把你的循环重构成这样的东西:
while (true) {
lock (_lock) {
Counter++;
Console.WriteLine("Thread {0} : the value of the counter is {1}",
name.ToString(), Counter);
if (Counter >= 20) {
break;
}
}
}