using System;
using System.Threading;
using System.Threading.Tasks;
namespace _1._41_Compare_and_Exchange_as_a_nonAtomic_operation
{
public class Program
{
static int value = 1;
public static void Main()
{
Task t1 = Task.Run(() =>
{
if (value == 1)
{
Thread.Sleep(1000);
value = 2;
}
});
Task t2 = Task.Run(() =>
{
value = 3;
});
Task.WaitAll(t1, t2);
Console.WriteLine(value); //Displays 2
}
}
}
我正在尝试使用以下方法将上述非原子操作转换为原子操作:
Interlocked.CompareExhange(ref value, newValue, compareTo);
我写的是
Interlocked.CompareExhange(ref value, value, value); //This doesn't look right!
和
Interlocked.CompareExhange(ref value, t2, t1); //will not compile
问题
- 有或没有 Interlocked.CompareExchange 值输出为 2?为什么?
- 引用 t1、t2 的正确方法是什么?
- 为什么我不能直接引用任务的输出? (值,t2,t1)
- 是否需要或什至必须进行某种转换?
- 据我了解,该值应该更新为 2(值 = 1),然后更新为 3,而不是当前输出(值 = 1,更新为 3,然后更新为 2)一次
Interlocked.CompareExchange
用来?
最佳答案
With or without Interlocked.CompareExchange value is output as 2? Why?
真正的答案是:巧合。您的代码是不确定的,其行为取决于操作系统线程调度程序。
但是...实际上一点也不奇怪 t1
在 t2
之前开始执行。在这种情况下,if (value == 1)
检查是在 t2
之前进行的有机会执行 value = 3;
.
总而言之,最可能的时间表是:
-
t1
:value
对照1
进行检查 -
t1
:t1
休眠一秒钟 -
t2
:value
设置为 3 -
t1
: 一秒后醒来 -
t1
:value
设置为 2
但正如我上面所说,这正是实践中发生的情况,但游览代码仍然是不确定的,如 t2
原则上可以在 t1
之前开始执行.
What is the correct way to reference t1, t2?
如果我正确理解你的问题,你的做法似乎是正确的。
Why can't I reference the output of the task directly? (value, t2, t1)
您开始void
任务,这些任务一开始就没有输出。他们由 Task
代表类型。
您可以启动一个返回如下结果的任务:
var t = Task.Run(() => {
// do anything
return 42;
});
在本例中,t
类型为 Task<int>
您将能够访问其 Result
任务结束时的属性(如果您尝试在任务完成之前访问 i,它将阻塞直到任务结束)。
Is some sort of conversion required or even necessary?
我不确定我是否理解你的问题。
As I understand the value should be updated to 2 (value =1) then updated to 3 instead of the current output (value =1, updates to 3 then updates it to 2) once Interlocked.CompareExchange is used?
差不多,是的。 Interlocked.CompareExchange
是原子。它将执行比较并在硬件级别一步设置值:
Interlocked.CompareExchange(ref value, 2, 1);
这是原子等价于:
if (value == 1)
value = 2;
如果您这样做,最终值将始终为 3
。因为两种不同的场景是可能的(这很容易,因为现在两个任务都包含单个原子语句):
t1
在t2
之前执行:-
t1
:value
对照1
进行检查,这是真的,所以value
设置为2
-
t2
:value
设置为 3
-
t2
在t1
之前执行:-
t2
:value
设置为 3 -
t1
:value
对照1
进行检查,这是错误的,所以value
保持不变
-
如您所见,您最终会得到 3
在这两种情况下。
关于c# - Interlocked.CompareExchange(引用值,newValue,compareTo),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34559084/