C#多线程和重新排序-什么';这是怎么回事?
我有以下代码:C#多线程和重新排序-什么';这是怎么回事?,c#,multithreading,race-condition,C#,Multithreading,Race Condition,我有以下代码: public static System.Int32 i = 0; static void Main(string[] args) { new Thread(Worker1) { IsBackground = true }.Start(); new Thread(Worker2) { IsBackground = true }.Start(); Console.WriteLine("Running...
public static System.Int32 i = 0;
static void Main(string[] args)
{
new Thread(Worker1) { IsBackground = true }.Start();
new Thread(Worker2) { IsBackground = true }.Start();
Console.WriteLine("Running... Press enter to quit");
Console.ReadLine();
}
static void Worker1(object _)
{
while (true)
{
var oldValue = i;
i++;
var newValue = i;
if (newValue < oldValue)
Console.WriteLine("{2}, i++ went backwards! oldValue={0}, newValue={1}!", oldValue, newValue, DateTime.Now.ToString("HH:MM:ss.fff"));
}
}
static void Worker2(object _)
{
while (true)
{
i++;
}
}
注意:这是在Windows7上的四核i7上运行的,具有超线程功能
据我所知,要么:
- 在读取oldValue和newValue之间,Thread2的增量约为40亿倍(但不完全如此!)。考虑到上面的数字和时间,我在接下来的2秒钟内中奖10次的可能性似乎更大
- CPU和编译器正在重新排序。。。这似乎是合乎逻辑的解释,但我不能很好地找出一系列可能导致这种情况的操作
为了澄清这个问题:作为教育练习的一部分,我有意寻找能够复制内存重新排序错误的代码。有很多方法可以解决这个问题,我主要感兴趣的是分析发生了什么
@Tymek已经给出了下面的答案(现在已经指出了,答案非常明显)。如果你想让旧值的赋值、i的增量和新值的赋值“同时”发生,你应该使用一个锁。 只需引入一个私有变量,然后在此变量上使用锁。这看起来像:
lock(lockObj)
{
var oldValue = i;
i++;
var newValue = i;
}
为了避免这个问题,您可以使用它来保证操作是原子的和线程安全的。当您使用i++时,它不是原子的,并且它的值可以在增量过程中更改(例如,从另一个线程更改)。您肯定知道i++不是原子的,看起来确实像这样:
17:08:17.020, i++ went backwards! oldValue=6124653, newValue=6113984!
17:08:17.057, i++ went backwards! oldValue=18764535, newValue=18752368!
17:08:17.086, i++ went backwards! oldValue=27236177, newValue=27236176!
17:08:17.087, i++ went backwards! oldValue=27550457, newValue=27535008!
17:08:17.130, i++ went backwards! oldValue=40251349, newValue=40235492!
17:08:17.137, i++ went backwards! oldValue=42339974, newValue=42323786!
17:08:17.142, i++ went backwards! oldValue=43828602, newValue=43828436!
17:08:17.149, i++ went backwards! oldValue=45969702, newValue=45959111!
17:08:17.158, i++ went backwards! oldValue=48705847, newValue=48705549!
17:08:17.230, i++ went backwards! oldValue=71199684, newValue=71199674!
- 将
从内存读取到寄存器i
- 递增寄存器
- 将寄存器写入
所在的内存i
- 返回
李>i
- 让我们
bei
李>100
- 线程2读取
并被中断李>100
- 线程1执行一段时间并将i递增到120(几个完整循环),然后将
读为i
,读取120
并将其递增到i
,并在121
var newValue=i之前中断代码>李>
- 线程2将
增加到i
并被中断李>101
- Thread one运行并执行
可能会发生这样的情况,操作系统在执行程序时需要一些资源,这会导致一种重新排序的感觉。只需期望使用多线程和多个非同步化操作,所有可能的排列都会发生——迟早会发生。您必须锁定所提供代码中的两个i++语句。只锁定一个不会有多大变化。var newValue=i
- 线程2将