我正在学习C#,目前正在学习线程。
这是一个在不同线程中多次向变量添加1的简单示例。
本书建议我可以使用Interlocked.increment(ref number)
替换+= 1
方法中的数字AddOne
,因此该值将被锁定,直到它在线程中更新为止。因此输出将如预期的那样1000, 2000, ..... 10000
。但我的输出仍为999, 1999, 2999, ...... 9999
。
只有在我取消注释Thread.Sleep(1000)
行后,输出才会正确,但即使没有使用Interlocked
。
有谁能解释这里发生了什么?
static void Main(string[] args)
{
myNum n = new myNum();
for (int i = 0;i<10; Interlocked.Increment(ref i))
{
for(int a =1;a<=1000; Interlocked.Increment(ref a))
{
Thread t = new Thread( new ThreadStart( n.AddOne));
t.Start();
}
//Thread.Sleep(1000);
Console.WriteLine(n.number);
}
}
class myNum
{
public int number = 0;
public void AddOne()
{
//number += 1;
Interlocked.Increment(ref number);
}
}
答案 0 :(得分:4)
您将在所有线程执行完毕之前打印出该值。您需要在打印前加入所有线程。
for(int a = 0; a < 1000; a++)
{
t[a].Join();
}
您需要将线程存储在数组或列表中。此外,您不需要任何for循环中的互锁指令。它们都只在一个线程(主线程)中运行。只有AddOne中的代码在多个线程中运行,因此需要同步。
答案 1 :(得分:0)
对我来说,使用此代码尝试实现的目标有点奇怪。您在任何地方都使用Interlocked.Increment
而没有明确的需求。
Interlocked.Increment
。在您的代码中,它仅为number
,因此您不需要i
和a
,只需使用i++
和a++
您要求的问题是,您只是不要等待您启动的所有线程完成其工作。看看Thread.Join()方法。您必须等待所有线程开始完成其工作。
在这个简单的测试中,你完成了Thread.Sleep(1000);
你做类似的等待,但假设所有线程在1000毫秒内完成是不正确的,所以只需使用Thread.Join()
。
如果您修改AddOne()
方法以使其开始执行的时间更长(例如向其中添加Thread.Sleep(1000)
),您会发现Thread.Sleep(1000);
不再有用。
我建议您详细了解ThreadPool vs Threads。另请查看Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4