c# - Interlocked.CompareExchange(引用值,newValue,compareTo)

标签 c# multithreading visual-studio-2015 task-parallel-library

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

问题

  1. 有或没有 Interlocked.CompareExchange 值输出为 2?为什么?
  2. 引用 t1、t2 的正确方法是什么?
  3. 为什么我不能直接引用任务的输出? (值,t2,t1)
  4. 是否需要或什至必须进行某种转换?
  5. 据我了解,该值应该更新为 2(值 = 1),然后更新为 3,而不是当前输出(值 = 1,更新为 3,然后更新为 2)一次 Interlocked.CompareExchange用来?

最佳答案

With or without Interlocked.CompareExchange value is output as 2? Why?

真正的答案是:巧合。您的代码是不确定的,其行为取决于操作系统线程调度程序。

但是...实际上一点也不奇怪 t1t2 之前开始执行。在这种情况下,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 。因为两种不同的场景是可能的(这很容易,因为现在两个任务都包含单个原子语句):

  • t1t2之前执行:

    • t1 :value对照1进行检查,这是真的,所以 value设置为2
    • t2 :value设置为 3
  • t2t1之前执行:

    • t2 :value设置为 3
    • t1 :value对照1进行检查,这是错误的,所以 value保持不变

如您所见,您最终会得到 3在这两种情况下。

关于c# - Interlocked.CompareExchange(引用值,newValue,compareTo),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34559084/

相关文章:

c# - Kinect:计算头部的俯仰角、偏航角、滚动角

c# - Windows SDK - C# - 调试进程退出,错误代码为 -1073741502

c# - 来自后台 worker 的文件对话框

windows - 无法阻止 Visual Studio 2015 在 "JavaScript language service is processing your request in the background..."的 JS 文件中滞后几秒钟?

typescript - 将 Visual Studio 中的 TypeScript 降级到 1.7

c# - 反序列化后 JSON 字段值变为 null

c# - 我可以在 C# 中获取和设置数组吗?

java - volatile 关键字 : is the variable I am using among two threads synchronized?

c++ - C++多线程关闭TCP连接

visual-studio-2015 - 使用 MSBuild 命令行创建 APK 错误(PackageForAndroid 或 SignAndroidPackage)