代码之家  ›  专栏  ›  技术社区  ›  relatively_random

异步和等待是否产生获取和释放语义?

  •  0
  • relatively_random  · 技术社区  · 5 年前

    我找不到明确的答案 async 方法总是生成发布语义,以及 await 总是生成获取语义。我想是的,否则 async/await 密码会是雷区吗?

    下面是一个例子:返回的值都保证 100*2 12345*2 ,没有任何明确的锁或屏障?

    private static async Task<(int, int)> AMethod()
    {
        // Runs on the original thread:
        var x = 100;
        var y = 12345;
    
        var task = Task.Run(() =>
        {
            // Can run on another thread:
            x *= 2;
            y *= 2;
    
            // Implicit return here, marking the task completed.
            // Release semantics or not?
        });
    
        await task; // Acquire semantics or not?
    
        // Runs on the original thread:
        return (x, y);
    }
    

    编辑:当然, Task.Run 还需要生成一个版本,并且在开始运行任务代码时需要获取。忘了原来的问题。

    0 回复  |  直到 5 年前
        1
  •  3
  •   canton7    5 年前

    是的,返回值都保证 100*2 12345*2 ,没有任何显式的锁或屏障。

    这是 Task.Run 而不是 await ,在这种情况下会产生内存障碍。

    引述 wonderful Albahari Threading in C# :

    下面隐式地生成完整的栅栏:

    • C的锁语句(monitor.enter/monitor.exit)
    • 联锁类上的所有方法(很快就会涵盖这些方法)
    • 使用线程池的异步回调——这些包括异步委托、APM回调和任务延续
    • 设置和等待信令构造
    • 任何依赖信号的东西,如开始或等待任务

    根据最后一点,以下是线程安全的:

    int x = 0;
    Task t = Task.Factory.StartNew (() => x++);
    t.Wait();
    Console.WriteLine (x);    // 1
    

    任务运行 包裹 ThreadPool.UnsafeQueueUserWorkItem ,它属于“使用线程池的异步回调”。

    Memory barrier generators 为了更全面地列出造成记忆障碍的事情。