首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Interlocked.CompareExchange(参考值,newValue,compareTo)

Interlocked.CompareExchange(参考值,newValue,compareTo)
EN

Stack Overflow用户
提问于 2016-01-01 19:02:15
回答 1查看 140关注 0票数 2
代码语言:javascript
复制
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

        }
    }
}

我试图利用以下方法将上述非原子操作转换为原子操作:

代码语言:javascript
复制
Interlocked.CompareExhange(ref value, newValue, compareTo);

我写成

代码语言:javascript
复制
 Interlocked.CompareExhange(ref value, value, value); //This doesn't look right!

代码语言:javascript
复制
Interlocked.CompareExhange(ref value, t2, t1); //will not compile

问题

  1. 是否有Interlocked.CompareExchange值输出为2?为什么?
  2. 引用t1,t2的正确方法是什么?
  3. 为什么我不能直接引用任务的输出?(价值,t2,t1)
  4. 是否需要某种形式的转换,甚至是必要的?
  5. 据我所知,一旦使用Interlocked.CompareExchange,应该将值更新为2 (value = 1),然后更新为3,而不是当前的输出(value = 1,更新到3,然后更新为2)?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-01 19:37:20

是否有Interlocked.CompareExchange值输出为2?为什么?

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

但是..。实际上,t1t2之前开始执行并不令人惊讶。在本例中,if (value == 1)检查是在t2有机会执行value = 3;之前进行的。

总而言之,最可能的时间表是:

  • t1:检查value1
  • t1t1睡了一秒
  • t2value设置为3
  • t1:一秒后醒来
  • t1value设置为2

但是,正如我前面所说的,这正是在实践中发生的事情,但是浏览代码仍然是不确定的,因为t2原则上可以在t1之前开始它的执行。

引用t1,t2的正确方法是什么?

如果我正确理解你的问题,你的做法似乎是正确的。

为什么我不能直接引用任务的输出?(价值,t2,t1)

您可以启动void任务,这些任务一开始没有输出。它们由Task类型表示。

您可以启动一个返回如下结果的任务:

代码语言:javascript
复制
var t = Task.Run(() => {
    // do anything
    return 42;
});

在本例中,t将是Task<int>类型,任务结束时您将能够访问它的Result属性(如果在任务完成之前尝试访问i,它将一直阻塞直到任务结束)。

是否需要某种形式的转换,甚至是必要的?

我不太明白你的问题。

据我所知,一旦使用Interlocked.CompareExchange,应该将值更新为2 (value =1),然后更新为3,而不是当前的输出(value =1,更新到3,然后更新为2)?

差不多,是的。Interlocked.CompareExchange是原子的。它将在硬件级别执行比较并在一步内设置值:

代码语言:javascript
复制
Interlocked.CompareExchange(ref value, 2, 1);

这是原子等效的:

代码语言:javascript
复制
if (value == 1)
    value = 2;

如果这样做,最终的值将永远是3。因为两种不同的场景是可能的(这很容易,因为现在这两个任务都包含一个原子语句):

  • t1t2之前执行
代码语言:javascript
复制
- `t1`: `value` is checked against `1`, which is true, so `value` is set to `2`
- `t2`: `value` is set to 3

  • t2t1之前执行
代码语言:javascript
复制
- `t2`: `value` is set to 3 
- `t1`: `value` is checked against `1`, which is false, so `value` is left unchanged

正如您所看到的,在这两种情况下,您都将得到3

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34559084

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档