728x90

 

.NET Documentation์˜ Task Cancellation ๋ฒˆ์—ญ ๋ฐ ๋‚ด์šฉ ์ถ”๊ฐ€ํ•˜์—ฌ ์ •๋ฆฌํ•œ ๊ธ€


์ž‘์—… ์ทจ์†Œํ•˜๊ธฐ

Task์™€ Task<TResult> ํด๋ž˜์Šค์—์„œ ์ทจ์†Œ ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ Task๋ฅผ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (๊ด€๋ฆฌ๋˜๋Š” ์Šค๋ ˆ๋“œ ์ทจ์†Œํ•˜๊ธฐ ์ฐธ๊ณ ) Task ํด๋ž˜์Šค์—์„œ Cancellation์€ ์‹คํ–‰ ์ค‘ ์ทจ์†Œ๋  delegate(Task๋กœ ๋“ฑ๋ก๋œ ์‹คํ–‰ ํ•จ์ˆ˜์˜ ์ฐธ์กฐ)์™€ ์ทจ์†Œ๋ฅผ ์š”์ฒญํ•œ ์ฝ”๋“œ์˜ ์ƒํ˜ธ ์ž‘์šฉ์œผ๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ์ทจ์†Œ ์š”์ฒญ ์ฝ”๋“œ์—์„œ CancellationTokenSource.Cancel() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค ์‚ฌ์šฉ์ž delegate๊ฐ€ ์›ํ•˜๋Š” ์‹œ์ ์— ์ข…๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, ์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ทจ์†Œ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

 

์ž‘์—… ์ข…๋ฃŒํ•˜๊ธฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ delegate๊ฐ€ return์— ๋„๋‹ฌํ•ด ์ข…๋ฃŒ๋˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋ ‡๊ฒŒ ์ข…๋ฃŒ๋œ ์ž‘์—… ์ธ์Šคํ„ด์Šค๋Š” Canceled(์ทจ์†Œ)๊ฐ€ ์•„๋‹ˆ๋ผ RanToCompletion(์„ฑ๊ณต์ ์œผ๋กœ ์ข…๋ฃŒ) ์ƒํƒœ๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.

delegate๋ฅผ ์ทจ์†Œ ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์‹คํ–‰ ์ทจ์†Œ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์ทจ์†Œ๊ฐ€ ์š”์ฒญ๋œ ํ† ํฐ์„ delegate์— ์ „๋‹ฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณดํ†ต ThrowIfCancellationRequested() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„, ์ทจ์†Œ ์š”์ฒญ(์‹คํ–‰ ์ทจ์†Œ ์˜ˆ์™ธ)์„ ๋ณด๋‚ธ ์ฝ”๋“œ์—์„œ delegate์˜ ์ƒํƒœ๊ฐ€ ์ทจ์†Œ๊ฐ€ ๋ ๋•Œ๊นŒ์ง€ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

 

 

์•„๋ž˜๋Š” ์‹คํ–‰ ์ทจ์†Œ ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Task ์ทจ์†Œ ๋ฐฉ์‹์˜ ๊ธฐ๋ณธ์ ์ธ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค. ํ† ํฐ์€ delegate์™€ ์ž‘์—… ์ธ์Šคํ„ด์Šค์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Run(() =>
        // Task๋กœ ์‹คํ–‰ํ•  delegate ์ •์˜
        {
            // ์ด๋ฏธ ์ทจ์†Œ๋œ ์ž‘์—…์ธ์ง€ ํ™•์ธ
            ct.ThrowIfCancellationRequested();

            bool moreToDo = true;
            while (moreToDo)
            {
                // ์˜ˆ์™ธ์ฒ˜๋ฆฌ ์ „ ์ง„ํ–‰ํ•ด์•ผํ•˜๋Š” ์ดˆ๊ธฐํ™” ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด
                // IsCancellationRequested ๊ฐ’์„ ์ฒดํฌํ•˜๋Š” If๋ฌธ ์ถ”๊ฐ€
                if (ct.IsCancellationRequested)
                {
                    // ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์ง„ํ–‰ํ•œ ๋’ค...
                    ct.ThrowIfCancellationRequested();
                }
            }
        }, tokenSource2.Token); // Task์—๋„ ๊ฐ™์€ ํ† ํฐ์„ ์ „๋‹ฌ


        // ์ฝ”๋“œ์—์„œ ์ทจ์†Œ ์š”์ฒญ ์‹คํ–‰!
        tokenSource2.Cancel();

        // ํ•ด๋‹น ์Šค๋ ˆ๋“œ์—์„œ ๊ณ„์† ์ง„ํ–‰ํ•ด๋„ ๋˜๊ณ ,
        // try-catch๋ฌธ์—์„œ ์ž‘์—…(task)์„ ๋Œ€๊ธฐํ•ด๋„ ๋œ๋‹ค.
        try
        {
            await task;
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
        }
        finally
        {
            tokenSource2.Dispose();
        }

        Console.ReadKey();
    }
}

Task์™€ child Task๋ฅผ ์ทจ์†Œํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋ผ๋Š” ๊ธ€์—์„œ ์ž์„ธํ•œ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ž‘์—… ์ธ์Šคํ„ด์Šค๋Š” ์‚ฌ์šฉ์ž ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰ ์ทจ์†Œ ์˜ˆ์™ธ๋ฅผ ๋ณด๋‚ด๋ฉด ๋ฐ›์€ ํ† ํฐ๊ณผ ์ž์‹ ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”(์ž‘์—… ์ƒ์„ฑ ์‹œ ์ธ์ž๋กœ ๋ฐ›์€) ํ† ํฐ์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋‘ ํ† ํฐ์ด ์„œ๋กœ ๊ฐ™๊ณ  ํ† ํฐ์˜ IsCancellationRequested ๊ฐ’์ด true์ด๋ฉด, ์œ ํšจํ•œ ์š”์ฒญ์œผ๋กœ ํ•ด์„ํ•˜๊ณ  Task๋ฅผ ์ทจ์†Œ ์ƒํƒœ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ Wait์ด๋‚˜ WaitAll ๋•Œ๋ฌธ์— ์ž‘์—… ๋Œ€๊ธฐ๊ฐ€ ์ง„ํ–‰๋œ๋‹ค๋ฉด, ์ž‘์—… ์ทจ์†Œ ์˜ˆ์™ธ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์™ธ๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ทจ์†Œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„์ˆ˜๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Task์˜ ์˜ˆ์™ธ ๊ฐ’์€ null์ž…๋‹ˆ๋‹ค.

 

๋งŒ์•ฝ ์˜ˆ์™ธ๊ฐ€ ๊ฐ์ง€๋œ ํ† ํฐ๊ณผ Task์˜ ํ† ํฐ์ด ์„œ๋กœ ๋‹ค๋ฅด๊ฑฐ๋‚˜ ํ† ํฐ์˜ IsCancellationRequested๊ฐ’์ด false๋ผ๋ฉด,  ์˜ˆ์™ธ๋Š” ์ผ๋ฐ˜์ ์ธ ์˜ˆ์™ธ๋กœ ์ทจ๊ธ‰๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Task๋Š” ์‹คํŒจ ์ƒํƒœ๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค. ์™„์ˆ˜๋œ Task์˜ ์ƒํƒœ๋Š” Status ํ”„๋กœํผํ‹ฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ทจ์†Œ ์š”์ฒญ์„ ๋ฐ›์„์ง€๋ผ๋„ Task๊ฐ€ ์ผ๋ถ€ ํ•ญ๋ชฉ์„ ๊ณ„์† ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

4์ค„ ์š”์•ฝ

1. TokenSource์—์„œ ์ทจ์†Œ ํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ , ์ด ํ† ํฐ์„ Task์™€ ์ด Task์—์„œ ์‹คํ–‰ํ•  delegate์— ์ „๋‹ฌํ•œ๋‹ค.

2. delegate์—๋Š” ๋ฐœ๊ธ‰๋ฐ›์€ ์ทจ์†Œ ํ† ํฐ์˜ ์ƒํƒœ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

3. delegate๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ ์›ํ•˜๋Š” ์‹œ์ ์—์„œ ์ทจ์†Œ ํ† ํฐ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š” ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

4. Task๊ฐ€ ์‹คํ–‰๋˜๋Š” Level(3์ด ์žˆ๋Š” ๋ ˆ๋ฒจ)์˜ ์ฝ”๋“œ์—์„œ๋Š” (try-catch๋ฌธ ๋“ฑ์œผ๋กœ) ํ† ํฐ์˜ ์˜ˆ์™ธ๋ฅผ ์ฒดํฌํ•˜๋‹ค๊ฐ€, ์˜ˆ์™ธ๊ฐ€ ์ƒ๊ธฐ๋ฉด TokenSource๋ฅผ ํ๊ธฐํ•˜๋„๋ก ํ•œ๋‹ค.

 

 

Dispose  vs  Cancel

์ทจ์†Œ ํ† ํฐ ์†Œ์Šค๋ฅผ Dispose ํ•˜๊ฑฐ๋‚˜ Cancel ํ•˜๊ฑฐ๋‚˜, ๋‘˜ ๋‹ค Task๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  Cancel ์ƒํƒœ๋กœ ์ „ํ™˜์‹œํ‚จ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ตณ์ด ํ† ํฐ ์†Œ์Šค๋ฅผ Cancel ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ญ˜๊นŒ.

 

ํ•œ๋ฒˆ ํ† ํฐ์„ ๋งŒ๋“  ๋’ค TokenSource๋ฅผ ๋” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํฌ๊ฒŒ ์ƒ๊ด€์ด ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Source๊ฐ€ ํ† ํฐ์„ ๊ณ„์† ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ Dispose๋กœ Source๋ฅผ ํ๊ธฐํ•œ๋‹ค๋ฉด, Dispose ์‹คํ–‰๊ณผ ํ† ํฐ ์ƒ์„ฑ ์ž‘์—… ๊ฐ„ Race Condition์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์ „์ฒ˜๋ฆฌ ํ™•์ธ ์ˆ˜๋‹จ์œผ๋กœ Cancel ์ž‘์—…์ด ์กด์žฌํ•œ๋‹ค. (์ด ๋ฌธ๋‹จ์˜ ๋‚ด์šฉ์€ ํ‹€๋ฆด ์ˆ˜๋„ ์žˆ์Œ)

 

 


์ฐธ๊ณ ์ž๋ฃŒ

 

728x90

+ Recent posts