Interlocked.increment 仍然没有解决值丢失的问题
我现在正在学习 C#,目前正在学习线程。
下面是一个在不同线程中多次向变量加 1 的简单示例。
这本书建议我可以使用 Interlocked.increment(ref number) 来替换 AddOne 方法中的数字 += 1 ,因此该值将被锁定,直到它在线程内更新。因此输出将如预期的那样为 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);
}
}
I'm studying C# right now and currently learning threading.
Here is a simple example to adding 1 to a variable multiple times within different threads.
The book suggested I can use Interlocked.increment(ref number)
to replace the number += 1
within the AddOne
method, therefore the value will be locked until it's updated within the thread. So the output will be 1000, 2000, ..... 10000
as expected. But My output is still 999, 1999, 2999, ...... 9999
.
Only after I uncomment the Thread.Sleep(1000)
line will the output be correct but even without the Interlocked
been used.
Can anyone explain what's happening here?
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);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您将在所有线程完成执行之前打印出该值。您需要在打印之前连接所有线程。
您需要将线程存储在数组或列表中。此外,您不需要在任何 for 循环中使用互锁指令。它们都只在一个线程(主线程)中运行。只有AddOne中的代码在多个线程中运行,因此需要同步。
You are printing out the value before all of the threads have finished executing. You need to join all of the threads before printing.
You'll need to store the threads in an array or list. Also, you don't need the interlocked instruction in any of the for loops. They all run in only one thread (the main thread). Only the code in AddOne runs in multiple threads and hence needs to by synchronized.
对我来说有点奇怪你想用这段代码实现什么。您在任何地方都使用
Interlocked.Increment
而没有明确的需要。访问可从不同线程访问的值需要
Interlocked.Increment
。在您的代码中,它只是number
,因此您不需要将其用于i
和a
,只需照常使用i++< /code> 和
a++
您要求的问题是您不等待您启动的所有线程完成其工作。查看 Thread.Join() 方法。您必须等待您启动的所有线程完成其工作。
在这个简单的测试中,您使用 Thread.Sleep(1000); 完成了;您执行了类似的等待,但假设所有线程在 1000 毫秒内完成是不正确的,因此只需使用 Thread.Join () 为此。
如果您修改
AddOne()
方法,使其开始执行更长的时间(例如向其中添加Thread.Sleep(1000)
),您会注意到Thread. Sleep(1000);
不再有帮助了。我建议阅读有关线程池与线程的更多信息。另请查看 并行编程模式:使用 .NET Framework 4 理解和应用并行模式
It a bit strange for me what you trying to achieve with this code. You are using
Interlocked.Increment
everywhere without explicit needs for it.Interlocked.Increment
required for access to values which can be accessed from different threads. In your code it is onlynumber
, so you don't require it fori
anda
, just use as usuallyi++
anda++
The problem you are asking for is that you just don't wait for all threads you started are completed its job. Take a look to Thread.Join() method. You have to wait while all of threads you are started completes its work.
In this simple test you are done with
Thread.Sleep(1000);
you do similar wait but its not correct to assume that all threads are complete in 1000 ms, so just useThread.Join()
for that.If you modify your
AddOne()
method so it starts to executes longer (e.g. addThread.Sleep(1000)
to it) you'll notice thatThread.Sleep(1000);
doesn't help any more.I'll suggest to read more about ThreadPool vs Threads. Also take a look to Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4