[英]should I *always* synchronize access to all double field/property/variables that used from more than one thread?
Note I tend to write lock-free code so I try to avoid any types of lock where possible. 注意我倾向于编写无锁代码,所以我尽可能避免任何类型的锁。 Instead I just use while(true)
loop because I have a lot of CPU power. 相反,我只是使用while(true)
循环,因为我有很多CPU能力。
According to that http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx double
variable update is not atomic. 根据http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx double
变量更新不是原子的。
I'm concerned about two issues: 我关心两个问题:
Questions: 问题:
Currently I use a lot of double
and decimal
variables/field/properties in my program and almost everythig works fine, so I really confused because I ofthen access them from different threads without any synchronization and that just works... But now I'm thinking that probably it would be better to use float
to have "built-in syncrhonization" 目前我在我的程序中使用了很多double
和decimal
变量/字段/属性,几乎每个都可以正常工作,所以我真的很困惑,因为我从不同的线程访问它们而没有任何同步,这只是有效...但现在我是认为使用float
进行“内置同步化”可能会更好
Yes, you need to do something. 是的,你需要做点什么。 double
and decimal
are not guaranteed to be atomic , so if you don't protect it you could get a torn value - ie your first bullet is entirely correct. double
和decimal
不保证是原子的 ,所以如果你不保护它,你可能会得到一个撕裂的价值 - 即你的第一颗子弹是完全正确的。
Re volatile
; volatile
; it is moot; 这是没有意义的; you are not allowed to have a volatile
field that is double
or decimal
, so the simplest answer is: lock
. 你不允许有一个double
或decimal
的volatile
字段,所以最简单的答案是: lock
。
Getting double
to fail is a royal PITA; double
失败是皇家PITA; but here's a torn-value example featuring decimal
(note the numbers of success/fail will change each iteration, even though the data is the same; this is the randomness of thread scheduling): 但这里是一个以decimal
为特征的撕裂值示例(注意成功/失败的数量将改变每次迭代,即使数据相同;这是线程调度的随机性):
using System;
using System.Threading;
static class Program
{
private static decimal shared ;
static void Main()
{
Random random = new Random(12345);
decimal[] values = new decimal[20];
Console.WriteLine("Values:");
for (int i = 0; i < values.Length; i++)
{
values[i] = (decimal)random.NextDouble();
Console.WriteLine(values[i]);
}
Console.WriteLine();
object allAtOnce = new object();
int waiting = 10;
shared = values[0];
int correct = 0, fail = 0;
for(int i = 0 ; i < 10 ; i++)
{
Thread thread = new Thread(() =>
{
lock(allAtOnce)
{
if (Interlocked.Decrement(ref waiting) == 0)
{
Monitor.PulseAll(allAtOnce);
} else
{
Monitor.Wait(allAtOnce);
}
}
for(int j = 0 ; j < 1000 ; j++)
{
for(int k = 0 ; k < values.Length ; k++)
{
Thread.MemoryBarrier();
var tmp = shared;
if(Array.IndexOf(values, tmp) < 0)
{
Console.WriteLine("Invalid value detected: " + tmp);
Interlocked.Increment(ref fail);
} else
{
Interlocked.Increment(ref correct);
}
shared = values[k];
}
}
if (Interlocked.Increment(ref waiting) == 10)
{
Console.WriteLine("{0} correct, {1} fails",
Interlocked.CompareExchange(ref correct, 0, 0),
Interlocked.CompareExchange(ref fail, 0, 0));
Console.WriteLine("All done; press any key");
Console.ReadKey();
}
});
thread.IsBackground = false;
thread.Start();
}
}
}
The key point; 关键点; the language makes no guarantees for the atomicity of double
. 语言不能保证 double
的原子性。 In reality, I expect you'll be fine, but most subtle problems caused by threading are due to using "I expect" instead of "I can guarantee". 实际上,我希望你会好起来,但线程引起的大多数细微问题都是由于使用了“我期待”而不是“我可以保证”。
If you want to guarantee that a block of code will be executed and finished before another thread manipulates it, surround that block of code with a lock
. 如果要保证在另一个线程操作它之前执行并完成一个代码块,请使用lock
包围该代码块。
You may be lucky, and threads may never battle over using a variable, but to make sure that it never happens, making sure precautions are taken wouldn't hurt. 你可能很幸运,线程可能永远不会使用变量争夺,但为了确保它永远不会发生,确保采取预防措施不会受到伤害。
Take a look here - this might help: http://msdn.microsoft.com/en-us/library/ms173179%28v=vs.80%29.aspx 看看这里 - 这可能会有所帮助: http : //msdn.microsoft.com/en-us/library/ms173179%28v=vs.80%29.aspx
a general answer would be - updates should be synchronized for all "shared" variables. 一般的答案是 - 应该为所有“共享”变量同步更新。 For exact answer need to see the code snippet. 要获得准确答案,请查看代码段。
Yes, you need to lock to be sure you get the correct result if multiple threads read/write a double at the same time. 是的,如果多个线程同时读取/写入一个double,则需要锁定以确保获得正确的结果。
Here's a failing example 这是一个失败的例子
[TestFixture]
public class DoubleTest
{
private double theDouble;
[Test]
public void ShouldFailCalledParallell()
{
theDouble = 0;
const int noOfTasks = 100;
const int noOfLoopInTask = 100;
var tasks = new Task[noOfTasks];
for (var i = 0; i < noOfTasks; i++)
{
tasks[i] = new Task(() =>
{
for (var j = 0; j < noOfLoopInTask; j++)
{
theDouble++;
}
});
}
foreach (var task in tasks)
{
task.Start();
}
Task.WaitAll(tasks);
theDouble.Should().Be.EqualTo(noOfTasks * noOfLoopInTask);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.