微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

异步方法中的内存障碍

如何解决异步方法中的内存障碍

此问题是对另一个有关记忆障碍的问题的答案的扩展:

https://stackoverflow.com/a/3556877/13085654

假设您以该代码示例为例,并对其进行调整以使该方法异步:

class Program
{
    static bool stop = false;

    public static void Main(string[] args)
    {
        var t = new Thread(async () =>
        {
            Console.WriteLine("thread begin");
            while (!stop)
            {
                if (false)
                {
                    await default(Task);
                }
            }
            Console.WriteLine("thread end");
        });
        t.Start();
        Thread.Sleep(1000);
        stop = true;
        Console.WriteLine("stop = true");
        Console.WriteLine("waiting...");
        t.Join();
    }
}

很显然,await永远不会被击中,但是只要它在方法中的存在就可以使Release编译的程序完成:注释掉await default(Task);会使程序再次挂起(即使您保留标记async方法)。这使我认为,基于该方法是否包含至少一个await,编译器生成的状态机存在显着差异。但是,将方法中被“实际击中”的部分的IL进行比较会显示几乎相同的指令,均包含以下循环构造:

          // start of loop,entry point: IL_0039

            // [14 13 - 14 26]
            IL_0039: ldsfld       bool Program::stop
            IL_003e: brfalse.s    IL_0039
          // end of loop

在IL级别,当出现await时,我看不到C#编译器正在做什么以注入内存屏障。有人对这是怎么回事有见识吗?

解决方法

有人对这是怎么回事有见识吗?

您编写的程序依赖于未定义的行为。因此,结果是不确定的。任何一种执行方式都可以产生任何结果。如果您要依靠任何一个结果,那么两种实现都不可接受。该语言无法保证,如果没有内存障碍,则变量不能不能观察到来自另一个线程的更新,仅保证它可以或不能。如果要强制读取要读取的更新值,请使用内存屏障,因为这就是它的用途。要强制该值反映其他线程的更改,请使用特定于该线程的变量的副本。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。