21. AsyncLocal<T> 와 ExecutionContext 흐름 (await 를 가로지르는 컨텍스트)

난이도 최상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// [주제] AsyncLocal<T> 와 ExecutionContext 흐름: await 를 가로지르는 논리적 컨텍스트
// 게임 서버에서 "현재 요청의 플레이어 ID·트레이스 ID" 같은 값을 파라미터로
// 일일이 넘기지 않고 흐름 전체에 실으려면 AsyncLocal 을 쓴다. 이 값은 스레드가
// 아니라 "논리적 비동기 흐름" 을 따라 전파된다. 반면 [ThreadStatic] 은 물리
// 스레드에 묶인다.
//
// [과제]
//   1) 출력 A~F 가 각각 무엇을 출력할지 예측하라(특히 D 와 F 에 주의).
//   2) AsyncLocal.Value 를 설정하면 그 변경이 "아래로(호출된 async)" 는 흐르지만
//      "위로(호출자)" 는 흐르지 않는 이유를, ExecutionContext 캡처/복원과
//      copy-on-write 관점에서 설명하라. 또 같은 목적을 [ThreadStatic] 으로
//      구현하면 await 이후 왜 값이 사라질 수 있는지 대비해 설명하라.
//   (내부 동작 설명은 answer.md 참조 — 먼저 스스로 예측/설명해 볼 것.)

using System;
using System.Threading.Tasks;

class AsyncContextDemo
{
    static AsyncLocal<int> Ctx = new AsyncLocal<int>();

    static async Task Main()
    {
        Ctx.Value = 1;
        Console.WriteLine("A: " + Ctx.Value);
        await Child();
        Console.WriteLine("D: " + Ctx.Value);

        var t1 = Branch(10);
        var t2 = Branch(20);
        int r1 = await t1;
        int r2 = await t2;
        Console.WriteLine("E: " + r1 + "," + r2);
        Console.WriteLine("F: " + Ctx.Value);
    }

    static async Task Child()
    {
        Console.WriteLine("B: " + Ctx.Value);
        Ctx.Value = 42;
        await Task.Yield();
        Console.WriteLine("C: " + Ctx.Value);
    }

    static async Task<int> Branch(int v)
    {
        Ctx.Value = v;
        await Task.Yield();
        return Ctx.Value;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.