43. ์Šค๋ ˆ๋“œ์™€ ํƒœ์Šคํฌ

2022. 4. 8. 09:18ยท๐Ÿ’ป Programming Language/C#
  • ํ”„๋กœ์„ธ์Šค(Process) : ์‹คํ–‰ํŒŒ์ผ์ด ์‹คํ–‰๋˜์–ด ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌ๋œ ์ธ์Šคํ„ด์Šค
  • ํ”„๋กœ์„ธ์Šค๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ(Thread)๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.
  • ์Šค๋ ˆ๋“œ๋Š” ์šด์˜์ฒด์ œ๊ฐ€ CPU๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ธฐ๋ณธ๋‹จ์œ„์ด๋ฉฐ, ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ฐง์ค„์ด๋ผ๋ฉด, ์Šค๋ ˆ๋“œ๋Š” ๋ฐง์ค„์„ ์ด๋ฃจ๊ณ  ์žˆ๋Š” ์‹ค์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ(Multi-Thread)๋ฅผ ์ด์šฉํ–ˆ์„๋•Œ์˜ ์žฅ๋‹จ์ .


์žฅ์ 
  1. ์‚ฌ์šฉ์ž ๋Œ€ํ™”ํ˜• ํ”„๋กœ๊ทธ๋žจ์—์„œ(์ฝ˜์†” ํ”„๋กœ๊ทธ๋žจ๊ณผ GUIํ”„๋กœ๊ทธ๋žจ ๋ชจ๋‘) ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ์‘๋‹ต์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ๊ผฝ์„ ์ˆ˜ ์žˆ๋‹ค.

    • ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํ”„๋กœ๊ทธ๋žจ์„ ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜๋Š”๋ฐ, ๋ณต์‚ฌํ•  ํ”ผ์ผ์ด ๋„ˆ๋ฌด ์ปค์„œ ์†Œ์š”์‹œ๊ฐ„์ด 30๋ถ„์ •๋„ ๊ฑธ๋ฆฐ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์ด ๋•Œ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹จ์ผ ์Šค๋ ˆ๋“œ๋กœ ๋งŒ๋“ ๋‹ค๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ์ž๊ฐ€ ์ทจ์†Œ ๋ช…๋ น์„ ๋‚ด๋ฆฌ๊ณ  ์‹ถ์–ด๋„ ํ”„๋กœ๊ทธ๋žจ์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜์‘ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ๋ณต์‚ฌ๋ฅผ ์ทจ์†Œํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค. ์ž‘์—…๊ด€๋ฆฌ์ž๋ฅผ ์ด์šฉํ•ด ๊ฐ•์ œ๋กœ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค์ง€ ์•Š๋Š” ํ•œ.. ์ด ํ”„๋กœ๊ทธ๋žจ์— ์‚ฌ์šฉ์ž์™€์˜ ๋Œ€ํ™”๋ฅผ ์œ„ํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด ํŒŒ์ผ๋ณต์‚ฌ๋ฅผ ํ•˜๋ฉด์„œ๋„ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋ช…๋ น์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

  2. ๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์Šค ๋ฐฉ์‹์— ๋น„ํ•ด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹์ด ์ž์›๊ณต์œ ๊ฐ€ ๋” ์‰ฝ๋‹ค๋Š” ์ ์ด ์žˆ๋‹ค.

    • ๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์Šค๋Š” GUI๊ฐ€ ์—†๋Š” ์›น์„œ๋ฒ„๊ฐ™์€ ์„œ๋ฒ„์šฉ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋งŽ์ด ์ทจํ•˜๋Š” ๊ตฌ์กฐ์ธ๋ฐ, ํ”„๋กœ์„ธ์Šค๋ผ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตํ™˜ํ•˜๋ ค๋ฉด ์†Œ์ผ“์ด๋‚˜ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๊ฐ™์€ IPC(Inter Process Communication)๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค. ๋ฐ˜๋ฉด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹์—์„œ๋Š” ๊ทธ์ € ์Šค๋ ˆ๋“œ๋ผ๋ฆฌ ์ฝ”๋“œ ๋‚ด์˜ ๋ณ€์ˆ˜๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ๋ฐ์ดํ„ฐ ๊ตํ™˜์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ํ”„๋กœ์„ธ์Šค๋ฅผ ๋„์šฐ๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ์™€ ์ž์›์„ ํ• ๋‹นํ•˜๋Š” ์ž‘์—…์€ (CPU ์‚ฌ์šฉ์‹œ๊ฐ„๋“ฑ์˜) ๋น„์šฉ์ด ๋น„์‹ผ๋ฐ, ์Šค๋ ˆ๋“œ๋ฅผ ๋„์šธ๋•Œ๋Š” ์ด๋ฏธ ํ”„๋กœ์„ธ์Šค์— ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ์™€ ์ž์›์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ์™€ ์ž์›์„ ํ• ๋‹นํ•˜๋Š” ๋น„์šฉ์„ ์ง€๋ถˆํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋‹จ์ 
  1. ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ๊นŒ๋‹ค๋กญ๋‹ค.
  2. ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค.
  3. ๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ฐ˜์˜ ์†Œํ”„ํŠธ์›จ์–ด๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž์‹ํ”„๋กœ์„ธ์Šค ์ค‘ ํ•˜๋‚˜์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์˜ํ–ฅ์ด ํ™•์‚ฐ๋˜์ง€ ์•Š์ง€๋งŒ, ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜์˜ ์†Œํ”„ํŠธ์›จ์–ด์—์„œ๋Š” ์ž์‹ ์Šค๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์ „์ฒด์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.
  4. ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ๋„ˆ๋ฌด ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉด ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.
    • ์Šค๋ ˆ๋“œ๊ฐ€ CPU๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์—… ๊ฐ„ ์ „ํ™˜(Context Switching)์„ ํ•ด์•ผํ•˜๋Š”๋ฐ, ์ด ์ž‘์—…๊ฐ„ ์ „ํ™˜์ด ๋งŽ์€ ๋น„์šฉ์„ ์†Œ๋ชจํ•œ๋‹ค. ๋งŽ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ๋„ˆ๋ฌด ์ž์ฃผ ์ž‘์—… ๊ฐ„ ์ „ํ™˜์„ ์ˆ˜ํ–‰ํ•˜๋‹ค ๋ณด๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹ค์ œ๋กœ ์ผ์„ ํ•˜๋Š” ์‹œ๊ฐ„์— ๋น„ํ•ด ์ž‘์—… ๊ฐ„ ์ „ํ™˜์— ์‚ฌ์šฉํ•˜๋Š” ์‹œ๊ฐ„์ด ์ปค์ง€๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ด ์ €ํ•˜๋œ๋‹ค.

์Šค๋ ˆ๋“œ ์‹œ์ž‘ํ•˜๊ธฐ

1. Thread์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด ๋•Œ ์ƒ์„ฑ์ž์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ํ•  ๋ฉ”์†Œ๋“œ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„˜๊ธด๋‹ค.
2. Thread.Start() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์Šค๋ ˆ๋“œ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.
3. Thread.Join() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
using System;
using System.Threading;

namespace ThreadEx
{

    class MainApp
    {
        static void DoSomething() // ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ํ•  ๋ฉ”์†Œ๋“œ
        {
            for(int i = 0; i < 5; i++)
            {
                Console.WriteLine($"DoSomething : {i}");
            }
            Thread.Sleep(10); 
            // sleep ๋ฉ”์†Œ๋“œ๋Š” ๋‹ค๋ฅธ์“ฐ๋ ˆ๋“œ๋„ CPU๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก, CPU์ ์œ ๋ฅผ ๋‚ด๋ ค๋†“๋Š”๋‹ค.
            // ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„์ด๋‹ค.
        }

        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(DoSomething)); // Thread์˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ

            Console.WriteLine("Start Threading...");
            t1.Start(); // ์Šค๋ ˆ๋“œ ์‹œ์ž‘

            for(int i = 0; i < 5; i++)
            {
                Console.WriteLine($"Main : {i}");
                Thread.Sleep(10);   
            }

            Console.WriteLine("Wating until thread stops...");
            t1.Join(); // ์Šค๋ ˆ๋“œ์˜ ์ข…๋ฃŒ ๋Œ€๊ธฐ

            Console.WriteLine("Finished");
        }
    }
} 
Output

Start Threading...
Main : 0
DoSomething : 0
DoSomething : 1
DoSomething : 2
DoSomething : 3
DoSomething : 4
Main : 1
Main : 2
Main : 3
Main : 4
Wating until thread stops...
Finished

์Šค๋ ˆ๋“œ ์ž„์˜๋กœ ์ข…๋ฃŒ์‹œํ‚ค๊ธฐ.


Thread t1 = new Thread(new ThreadStart(DoSomething)); // Thread์˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ

t1.Start();

t1.Abort(); // => ์Šค๋ ˆ๋“œ ์ทจ์†Œ ์ข…๋ฃŒ

t1.Join();
  • Abort()๋ฉ”์†Œ๋“œ๋Š” ์„ ์–ธ ํ›„ join๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ํ•ฉ์ณ์ค˜์•ผํ•จ. Abort()์ž์ฒด์ ์œผ๋กœ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์„ ์กฐ๊ธˆ์€ ์—ผ๋‘ํ•ด์•ผํ•˜๊ธฐ์—..

  • ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค ์‚ฌ์ด์—์„œ Abort ๋ฉ”์†Œ๋“œ์˜ ์‚ฌ์šฉ์€ ๊ธˆ๊ธฐ์‹œ ๋˜์–ด์žˆ๊ธฐ์— ๊ฐ€๊ธ‰์  ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. => ์ž˜๋ชปํ•˜๋ฉด ๊ณต์œ ์ž์›์ด ์ž ๊ธด์ฑ„๋กœ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜์–ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ๋„ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Œ.

using System;
using System.Threading;

namespace ThreadEx
{
    class SideTask
    {
        int count;

        public SideTask(int count)
        {
            this.count = count;
        }

        public void KeepAlive()
        {
            try
            {
                while(count > 0)
                {
                    Console.WriteLine($"{count--} left");
                    Thread.Sleep(10);
                }
                Console.WriteLine("count : 0");
            }
            catch(ThreadAbortException e)
            {
                Console.WriteLine(e);
                Thread.ResetAbort();
            }
            finally
            {
                Console.WriteLine("Clearing resource...");
            }
        }
    }
    class MainApp
    {
        static void Main(string[] args)
        {
            SideTask st = new SideTask(100);
            Thread t1 = new Thread(new ThreadStart(st.KeepAlive));
            t1.IsBackground = false;

            Console.WriteLine("Starting thread ... ");
            t1.Start();

            Thread.Sleep(100);

            Console.WriteLine("Aborting thread ... ");
            t1.Abort();

            Console.WriteLine("Waiting until thread stops ... ");
            t1.Join();

            Console.WriteLine("Finished");
        }
    }
} 
Output

Starting thread ...
100 left
99 left
98 left
97 left
96 left
95 left
94 left
Aborting thread ...
93 left
Unhandled exception. 92 left
System.PlatformNotSupportedException: Thread abort is not supported on this platform.
   at System.Threading.Thread.Abort()
   at ThreadEx.MainApp.Main(String[] args) in C:\Users\shkim\source\repos\ClassEx\practice1\Program.cs:line 51
91 left
90 left
89 left
88 left
87 left
86 left
85 left
  • ํ˜„์žฌ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ํ”Œ๋žซํผ์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋“ฏํ•จ.
ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค ์‚ฌ์ด์—์„œ Abort ๋ฉ”์†Œ๋“œ์˜ ์‚ฌ์šฉ์€ `๊ธˆ๊ธฐ์‹œ` ๋˜์–ด์žˆ๊ธฐ์— `๊ฐ€๊ธ‰์  ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฒƒ์„ ์ถ”์ฒœ`ํ•œ๋‹ค. 
=> ์ž˜๋ชปํ•˜๋ฉด ๊ณต์œ ์ž์›์ด ์ž ๊ธด์ฑ„๋กœ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜์–ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ๋„ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Œ.
  • ์œ„์™€ ๊ฐ™์€ ์ด์œ  ๋•Œ๋ฌธ์— ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ผ์ง€๋„ ๋ชจ๋ฅด๊ฒ ์Œ..

์Šค๋ ˆ๋“œ์˜ ์ผ์ƒ๊ณผ ์ƒํƒœ ๋ณ€ํ™”

์ƒํƒœ ์„ค๋ช…
Unstarted ์Šค๋ ˆ๋“œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ํ›„ Thread.Start() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์˜ ์ƒํƒœ
Running ์Šค๋ ˆ๋“œ๊ฐ€ ์‹œ์ž‘ํ•˜์—ฌ ๋™์ž‘์ค‘์ธ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. Unstarted ์ƒํƒœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ Thread.Start()๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ด ์ƒํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
Suspended ์Šค๋ ˆ๋“œ์˜ ์ผ์‹œ ์ค‘๋‹จ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์Šค๋ ˆ๋“œ๋ฅผ Thread.Suspend() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ด ์ƒํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฉฐ, Suspended์ƒํƒœ์ธ ์Šค๋ ˆ๋“œ๋Š” Thread.Resume() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋‹ค์‹œ Running ์ƒํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ.
WaitSleepJoin ์Šค๋ ˆ๋“œ๊ฐ€ ๋ธ”๋ก(Block)๋œ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ„. ์ƒํƒœ์ด๋ฆ„์ด block์ด ์•„๋‹Œ WaitSleepJoin์ธ ์ด์œ ๋Š” ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•ด Monitor.Enter(), Thread.Sleep() ๋˜๋Š” Thread.Join() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ด ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ.
Aborted ์Šค๋ ˆ๋“œ๊ฐ€ ์ทจ์†Œ๋œ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. Thread.Abort() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ด ์ƒํƒœ๊ฐ€ ๋จ. Aborted ์ƒํƒœ๊ฐ€ ๋œ ์Šค๋ ˆ๋“œ๋Š” ๋‹ค์‹œ Stopped ์ƒํƒœ๋กœ ์ „ํ™˜๋˜์–ด ์™„์ „ํžˆ ์ค‘์ง€๋จ.
Stopped ์ค‘์ง€๋œ ์Šค๋ ˆ๋“œ์˜ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ„. Abort() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰์ค‘์ธ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ์ด ์ƒํƒœ๊ฐ€ ๋จ.
Background ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ„. Foreground ์Šค๋ ˆ๋“œ๋Š” ํ•˜๋‚˜๋ผ๋„ ์‚ด์•„์žˆ๋Š”ํ•œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์ง€ ์•Š์ง€๋งŒ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ”„๋กœ์„ธ์Šค๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜๊ฐ€ ์•„๋‹ˆ๋ผ 10๊ฐœ๊ฐ€ ์‚ด์•„์žˆ์–ด๋„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ๊ณ  ์‚ฌ๋Š” ๊ฒƒ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Œ. ํ•˜์ง€๋งŒ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์œผ๋ฉด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋“ค๋„ ๋ชจ๋‘ ์ฃฝ์Œ. Thread.IsBackground ์†์„ฑ์— true๊ฐ’์„ ์ž…๋ ฅํ•จ์œผ๋กœ์จ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์ƒํƒœ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ.
  • ์ด๋“ค ThreadState ์—ด๊ฑฐํ˜•์˜ ๋ฉค๋ฒ„๋“ค์€ Flags ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • Flags ์†์„ฑ์€ ์ž์‹ ์ด ์ˆ˜์‹ํ•˜๋Š” ์—ด๊ฑฐํ˜•์„ ๋น„ํŠธ ํ•„๋“œ, ์ฆ‰ ํ”Œ๋ž˜๊ทธ ์ง‘ํ•ฉ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ์Šค๋ ˆ๋“œ๋Š” ๋‘๊ฐ€์ง€ ์ด์ƒ์˜ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. => ์ด ๋‘๊ฐ€์ง€ ์ด์ƒ์˜ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ด Flags ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ์ˆ˜์‹๋˜์–ด์žˆ๋Š”๊ฒƒ.

๋น„ํŠธ ํ•„๋“œ(Bit Field)
  • ์Šค๋ ˆ๋“œ๋Š” ๋™์‹œ์— ๋‘ ๊ฐ€์ง€ ์ด์ƒ์˜ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ
  • ์˜ˆ๋ฅผ๋“ค์–ด Suspended ์ƒํƒœ์ด๋ฉด์„œ WaitSleepJoin ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜๋„ ์žˆ๊ณ , Background ์ƒํƒœ์ด๋ฉด์„œ Stopped ์ƒํƒœ์ผ ์ˆ˜๋„ ์žˆ์Œ
  • ThreadState๋Š” ๋‘ ๊ฐ€์ง€ ์ด์ƒ์˜ ์ƒํƒœ๋ฅผ ๋™์‹œ์— ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ด Flags ์• ํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ์ˆ˜์‹๋˜์–ด ์žˆ์Œ
    • Flags => ์ž์‹ ์ด ์ˆ˜์‹ํ•˜๋Š” ์—ด๊ฑฐํ˜•์„ ๋น„ํŠธํ•„๋“œ(Bit Field),์ฆ‰ ํ”Œ๋ž˜๊ทธ ์ง‘ํ•ฉ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ„
using System;
using System.Threading;

namespace UsingThreadState
{
    class MainApp
    {
        private static void PrintThreadState(ThreadState state)
        {
            Console.WriteLine("{0,-16} : {1}", state,(int) state);
        }

        static void Main(string[] args)
        {
            PrintThreadState(ThreadState.Running);
            PrintThreadState(ThreadState.StopRequested);
            PrintThreadState(ThreadState.SuspendRequested);
            PrintThreadState(ThreadState.Background);
            PrintThreadState(ThreadState.Unstarted);
            PrintThreadState(ThreadState.Stopped);
            PrintThreadState(ThreadState.WaitSleepJoin);
            PrintThreadState(ThreadState.Suspended);
            PrintThreadState(ThreadState.AbortRequested);
            PrintThreadState(ThreadState.Aborted);
            PrintThreadState(ThreadState.Aborted | ThreadState.Stopped);
        }
    }
}
Output

Running          : 0
StopRequested    : 1
SuspendRequested : 2
Background       : 4
Unstarted        : 8
Stopped          : 16
WaitSleepJoin    : 32
Suspended        : 64
AbortRequested   : 128
Aborted          : 256
Stopped, Aborted : 272
  • ThreadState ํ•„๋“œ๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋น„ํŠธ์—ฐ์‚ฐ์„ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • ThreadState ์—ด๊ฑฐํ˜•์ด ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ๋™์‹œ์— ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ ธ ์žˆ๋‹ค.

๋น„ํŠธํ•„๋“œ๋ฅผ ์ด์šฉํ•ด ํ‘œํ˜„ํ•œ ์“ฐ๋ ˆ๋“œ์˜ ์ƒํƒœ
์ƒํƒœ ์‹ญ์ง„์ˆ˜ ์ด์ง„์ˆ˜
Running 0 000000000
StopRequested 1 000000001
SuspendedRequested 2 000000010
Background 4 000000100
Unstarted 8 000001000
Stopped 16 000010000
WatiSleepJoin 32 000100000
Suspended 64 001000000
AbortRequested 128 010000000
Aborted 256 100000000

์ธํ„ฐ๋ŸฝํŠธ(Interrupt) : ์Šค๋ ˆ๋“œ๋ฅผ ์ž„์˜๋กœ ๋ฉˆ์ถ”๋Š” ๋˜ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•

  • ๋ณธ๋ž˜ ์Šค๋ ˆ๋“œ๋Š” ์ˆ˜๋ช…์„ ๋‹คํ•ด ์Šค์Šค๋กœ ์ข…๋ฃŒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹๋‹ค. ๋ถˆ๊ฐ€ํ”ผํ•˜๊ฒŒ ์Šค๋ ˆ๋“œ๋ฅผ ๊ฐ•์ œ๋กœ ์ข…๋ฃŒ์‹œ์ผœ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ Thread.Abort() ๋ฉ”์†Œ๋“œ๋Š” ๋„ˆ๋ฌด ๋ฌด์ž๋น„ํ•˜๋‹ค. Abort()๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ• ๋•Œ๋Š” ๋„์ค‘์— ๊ฐ•์ œ๋กœ ์ค‘๋‹จ๋œ๋‹ค ํ•ด๋„ ํ”„๋กœ์„ธ์Šค ์ž์‹ ์ด๋‚˜ ์‹œ์Šคํ…œ์— ์˜ํ–ฅ์ด ์—†๋Š” ์ž‘์—…์— ํ•œํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ์Šค๋ ˆ๋“œ๊ฐ€ ์ˆ˜ํ–‰ ์ค‘์ธ ์ž‘์—…์ด ๊ฐ•์ œ๋กœ ์ค‘๋‹จ๋˜๋Š” ๊ฒฝ์šฐ ์‹œ์Šคํ…œ์— ์•…์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์กฐ๊ธˆ ๋” ๋ถ€๋“œ๋Ÿฌ์šด ๋ฐฉ๋ฒ•์„ ํƒํ•ด์•ผ ํ•œ๋‹ค.
  • Thread.Interrupt() ๋ฉ”์†Œ๋“œ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ํ•œ์ฐธ ๋™์ž‘์ค‘์ธ ์ƒํƒœ(Running ์ƒํƒœ)๋ฅผ ํ”ผํ•ด์„œ WaitJoinSleep ์ƒํƒœ์— ๋“ค์–ด๊ฐ”์„ ๋•Œ ThreadInterruptedException ์˜ˆ์™ธ๋ฅผ ๋˜์ ธ ์Šค๋ ˆ๋“œ๋ฅผ ์ค‘์ง€์‹œํ‚จ๋‹ค. => ์ด๋Ÿฌํ•œ ํŠน์ง• ๋•Œ๋ฌธ์— ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ์ตœ์†Œํ•œ ์ฝ”๋“œ๊ฐ€ "์ ˆ๋Œ€๋กœ ์ค‘๋‹จ๋˜๋ฉด ์•ˆ๋˜๋Š”" ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์„ ๋•Œ๋Š” ์ค‘๋‹จ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ณด์žฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
using System;
using System.Security.Permissions;
using System.Threading;

namespace InterruptingThread
{
    class SideTask
    {
        int count;

        public SideTask(int count)
        {
            this.count = count;
        }

        public void KeepAlive()
        {
            try
            {
                Console.WriteLine("Running thread isn't gonna be interrupted");
                Thread.SpinWait(1000000000);
                // SpinWait() ๋ฉ”์†Œ๋“œ๋Š” ์›๋ž˜ ์‚ฌ์šฉํ•  ์ผ์ด ๋ณ„๋กœ ์—†๋‹ค
                // ์ด ๋ฉ”์†Œ๋“œ๋Š” Sleep()๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์Šค๋ ˆ๋“œ๋ฅผ ๋Œ€๊ธฐํ•˜๊ฒŒ ํ•˜์ง€๋งŒ Sleep()๊ณผ ๋‹ฌ๋ฆฌ ์Šค๋ ˆ๋“œ๊ฐ€ Running ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ฒŒํ•จ/.

                while(count > 0)
                {
                    Console.WriteLine("{0} left", count--);

                    Console.WriteLine("Entering into WaitJoinSleep State...");
                    Thread.Sleep(10);
                }
                Console.WriteLine("Count : 0");
            }
            catch(ThreadInterruptedException e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                Console.WriteLine("Clearing resource ...");
            }
        }
    }    
    class MainApp
    {
        static void Main(string[] args)
        {
            SideTask task = new SideTask(100);
            Thread t1 = new Thread(new ThreadStart(task.KeepAlive));
            t1.IsBackground = false;

            Console.WriteLine("Starting thread...");
            t1.Start();

            Thread.Sleep(100);

            Console.WriteLine("Interrupting thread...");
            t1.Interrupt();

            Console.WriteLine("Waiting until thread stops...");
            t1.Join();

            Console.WriteLine("Finished");
        }
    }
}
Output

Starting thread...
Running thread isn't gonna be interrupted
Interrupting thread...
Waiting until thread stops...
100 left
Entering into WaitJoinSleep State...
System.Threading.ThreadInterruptedException: Thread was interrupted from a waiting state.
   at System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
   at System.Threading.Thread.Sleep(Int32 millisecondsTimeout)
   at InterruptingThread.SideTask.KeepAlive() in C:\Users\shkim\source\repos\ClassEx\practice1\Program.cs:line 30
Clearing resource ...
Finished
  • Main๋ฉ”์†Œ๋“œ ๋‚ด Interrupt() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์— ์Šค๋ ˆ๋“œ๊ฐ€ Running ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด SpinWait() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉ
  • ํ•ด๋‹น Main๋ฌธ ๋‚ด interrupt() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ ์Šค๋ ˆ๋“œ๋Š” KeepAlive ๋ฉ”์†Œ๋“œ ๋‚ด์˜ sleep(10)์— ์˜ํ•ด WaitSleepJoin ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ€๊ณ  ์ด๋•Œ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋ฐœ์ƒํ•จ.

์Šค๋ ˆ๋“œ ๊ฐ„์˜ ๋™๊ธฐํ™”

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ ์Šค๋ ˆ๋“œ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ž์›์„ ๊ณต์œ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.
    Ex) ํŒŒ์ผ ํ•ธ๋“ค์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์ปค๋„ฅ์…˜, ๋ฉ”๋ชจ๋ฆฌ์— ์„ ์–ธํ•œ ๋ณ€์ˆ˜ ๋“ฑ
  • ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ๋Š” ๋ณธ๋ž˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋–ค ์ž์›์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ฑด ์ƒ๊ด€์—†์ด ๊ฐ‘์ž๊ธฐ ๋ผ์–ด๋“ค์–ด ์ž๊ธฐ ์ œ๋ฉ‹๋Œ€๋กœ ์‚ฌ์šฉํ•ด๋ฒ„๋ฆฌ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋‹ค๋ฐ˜์‚ฌ์ด๋‹ค. ์ด๋Ÿฌํ•œ ์Šค๋ ˆ๋“œ์˜ ๊ธฐ์งˆ์„ ๊ทธ๋Œ€๋กœ ๋‘๋ฉด ์†Œํ”„ํŠธ์›จ์–ด๋“ค์€ ๋ชจ๋‘ ์—‰๋ง์ด ๋˜์–ด๋ฒ„๋ฆด ๊ฒƒ์ž„. => ์ฆ‰, ์Šค๋ ˆ๋“œ๋“ค์ด ์ •์—ฐํ•˜๊ฒŒ ์ž์›์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์งˆ์„œ๋ฅผ ์žก์•„์•ผํ•จ
    • ์ด์ฒ˜๋Ÿผ ์Šค๋ ˆ๋“œ๋“ค์ด ์ˆœ์„œ๋ฅผ ๊ฐ–์ถ”์–ด ์ž์›์„ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์„ ์ผ์ปฌ์–ด "๋™๊ธฐํ™”(Synchronization)" ๋ผ๊ณ  ํ•จ.
    • ์ด ๋™๊ธฐํ™” ์ž‘์—…์„ ์ œ๋Œ€๋กœ ํ•˜๋Š” ๊ฒƒ์ด์•ผ๋ง๋กœ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์™„๋ฒฝํ•˜๊ฒŒ ํ•˜๋Š” ๊ธธ
  • ์Šค๋ ˆ๋“œ ๋™๊ธฐํ™”์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์‚ฌํ•ญ์€ ์ž์›์„ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณด์žฅ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
    • ์ด๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด .Net ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” lock ํ‚ค์›Œ๋“œ์™€ Monitor ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. => ํ•˜๋Š” ์ผ์€ lock ํ‚ค์›Œ๋“œ์™€ Monitor ํด๋ž˜์Šค ๋‘˜ ๋‹ค ๋น„์Šทํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” lock ํ‚ค์›Œ๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ์ง€๋งŒ ์„ฌ์„ธํ•œ ๋™๊ธฐํ™” ์ œ์–ด ๊ธฐ๋Šฅ์€ Monitorํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์ œ๊ณตํ•œ๋‹ค. => ์ƒํ™ฉ์— ๋งž์ถฐ ์‚ฌ์šฉํ•˜๋ผ๋Š” ๋ง์ด๊ฒ ์ฅฌ~?

lock ํ‚ค์›Œ๋“œ๋กœ ๋™๊ธฐํ™”ํ•˜๊ธฐ

  • ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜(Critical Section) : ํ•œ๋ฒˆ์— ํ•œ ์Šค๋ ˆ๋“œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์˜์—ญ => ํ•ด๋‹น ์ฝ”๋“œ ์˜์—ญ์—๋Š” ํ•œ ๋ฒˆ์— ํ•œ ์Šค๋ ˆ๋“œ ํ˜น์€ ํ”„๋กœ์„ธ์Šค๋งŒ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์ž์›์ด ์กด์žฌํ•˜๊ธฐ์— ๋ฎคํ…์Šค(Mutex) ๋˜๋Š” ์„ธ๋งˆํฌ์–ด(Semaphore)๋ฅผ ํ†ตํ•ด ์ œ์–ดํ•ด์ค€ ๊ฒƒ ๊ฐ™์€ ๊ธฐ์–ต์ด ์žˆ๋‹ค.
  • C# ์—์„œ๋Š” lockํ‚ค์›Œ๋“œ๋กœ ๊ฐ์‹ธ์ฃผ๊ธฐ๋งŒ ํ•ด๋„ ํ‰๋ฒ”ํ•œ ์ฝ”๋“œ๋ฅผ ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.
using System;
using System.Threading;

class Counter
{
    public int count = 0;

    public void Increase()
    {
        count += 1;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Counter obj = new Counter();
        Thread t1 = new Thread(new ThreadStart(obj.Increase));
        Thread t2 = new Thread(new ThreadStart(obj.Increase));
        Thread t3 = new Thread(new ThreadStart(obj.Increase));

        t1.Start();
        t2.Start();
        t3.Start();

        t1.Join();
        t2.Join();
        t3.Join();

        Console.WriteLine(obj.count);
    }
}
  • ์œ„์˜ ์ฝ”๋“œ๋Š” ์Šค๋ ˆ๋“œ๋“ค์ด ์‚ฌ์ด๊ฐ€ ์ข‹๋‹ค๋ฉด ๊ฒฐ๊ณผ๊ฐ€ 3์ด ๋‚˜์˜ฌ ๊ฒƒ์ด๋‹ค
  • ํ•˜์ง€๋งŒ ๊ฒฐ๊ณผ๊ฐ’์˜ ๋ฒ”์œ„๋Š” 1 ~ 3 ์ด๋‹ค.
  • ์–ธ์ œ ์–ด๋–ค ์Šค๋ ˆ๋“œ๊ฐ€ obj์˜ Increase() ๋ฉ”์†Œ๋“œ์—์„œ count ๊ฐ’์„ ์‚ฌ์šฉํ• ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค
    • count => ๊ณต์œ  ์ž์›
  • ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด์„œ count += 1 ์ฝ”๋“œ๋ฅผ ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ํ•˜๊ณ  ์žˆ์„ ๋•Œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋กํ•˜๋Š” ์žฅ์น˜๊ฐ€ ํ•„์š”ํ•จ.
  • ์—ฌ๊ธฐ์„œ lockํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉ
using System;
using System.Threading;

class Counter
{
    public int count = 0;
    private readonly object thisLock = new object();    

    public void Increase()
    {
        lock ( thisLock )
        { 
        count += 1;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Counter obj = new Counter();
        Thread t1 = new Thread(new ThreadStart(obj.Increase));
        Thread t2 = new Thread(new ThreadStart(obj.Increase));
        Thread t3 = new Thread(new ThreadStart(obj.Increase));

        t1.Start();
        t2.Start();
        t3.Start();

        t1.Join();
        t2.Join();
        t3.Join();

        Console.WriteLine(obj.count);
    }
}
Output

3
  • ์œ„์—์„œ ์ฒ˜๋Ÿผ lock ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•จ
  • ์—ฌ๊ธฐ์„œ์˜ ๋™์ž‘์€ ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ๋“ค์ด lock()์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์žˆ๋Š” thisLock์„ ๋Œ๋ ค๊ฐ€๋ฉฐ ํ•ด๋‹น thisLock์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ๋“ค๋งŒ์ด ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด ๊ณผ์ •์—์„œ thisLock์„ ์–ป์ง€ ๋ชปํ•œ ์Šค๋ ˆ๋“œ๋“ค์€ thisLock์„ ๋‹ฌ๋ผ๊ณ  ์˜†์—์„œ ์ง•์ง•๊ฑฐ๋ฆฌ๋Š”๋ฐ ์ด๋Ÿฐ ๊ฒฝ์šฐ ์†Œํ”„ํŠธ์›จ์–ด์˜ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ๋–จ์–ด์ง„๋‹ค. => ๋”ฐ๋ผ์„œ ์Šค๋ ˆ๋“œ์˜ ๋™๊ธฐํ™”๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ๋Š” ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜์„ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ณณ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

  • ํ•œํŽธ lock ํ‚ค์›Œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด๋Š” ์ฐธ์กฐํ˜•์ด๋ฉด ์–ด๋А ๊ฒƒ์ด๋“  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ public ํ‚ค์›Œ๋“œ ๋“ฑ์„ ํ†ตํ•ด ์™ธ๋ถ€ ์ฝ”๋“œ์—์„œ๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์Œ ์„ธ๊ฐ€์ง€๋Š” ์ ˆ๋Œ€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ๋ฅผ ๊ถŒํ•จ
    • ๋ฌธ๋ฒ•์ ์œผ๋กœ ๋ฌธ์ œ๊ฐ€ ์—†์–ด ์ปดํŒŒ์ผ์‹œ์— ์—๋Ÿฌ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์•„ ๋” ๊ณจ์น˜์•„ํ””
๊ฐ์ฒด ์„ค๋ช…
this ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์™ธ๋ถ€์—์„œ๋„ ์ž์ฃผ ์‚ฌ์šฉ๋œ๋‹ค. ์ž์ฃผ ์ •๋„๊ฐ€ ์•„๋‹ˆ๊ณ  ๊ฑฐ์˜ ํ•ญ์ƒ๊ทธ๋ ‡๊ธฐ์— lock(this)๋Š” ๋‚˜์œ ๋ฒ„๋ฆ‡!
Type ํ˜•์‹ typeof ์—ฐ์‚ฐ์ž๋‚˜ object ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ๋ฌผ๋ ค๋ฐ›์€ GetType() ๋ฉ”์†Œ๋А๋Š” Type ํ˜•์‹์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ฆ‰, ์ฝ”๋“œ์˜ ์–ด๋А ๊ณณ์—์„œ๋‚˜ ํŠน์ • ํ˜•์‹์— ๋Œ€ํ•œ Type ๊ฐ์ฒด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. lock(typeof(SomeClass)) ๋‚˜ lock(obj.GetType()) ์€ ํ”ผํ•ด๋ผ ์ œ๋ฐœ!
string ํ˜•์‹ ์ ˆ๋Œ€ string ๊ฐ์ฒด๋กœ lock ํ•˜์ง€ ๋งˆ๋ผ "abc" ๋Š” ์–ด๋–ค ์ฝ”๋“œ์—์„œ๋“  ์–ป์–ด๋‚ผ ์ˆ˜ ์žˆ๋Š” string ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. lock("abc") ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์“ฐ๋Š” ์ง“์€ ํ”ผํ•ด๋ผ!

lock ํ‚ค์›Œ๋“œ๋กœ ๋™๊ธฐํ™”ํ•˜๊ธฐ ์‚ฌ์šฉ ์˜ˆ์ œ
using System;
using System.Threading;

namespace Synchronize
{
    class Counter
    {
        const int LOOP_COUNT = 1000;

        readonly object thisLock;

        private int count;
        public int Count
        {
            get { return count; }
        }

        public Counter()
        {
            thisLock = new object();
            count = 0;
        }

        public void Increase()
        {
            int loopCount = LOOP_COUNT;
            while (loopCount-- > 0)
            {
                lock (thisLock)
                {
                    count++;
                }
                Thread.Sleep(1);
            }
        }

        public void Decrease()
        {
            int loopCount = LOOP_COUNT;
            while(loopCount-- > 0)
            {
                lock (thisLock)
                {
                    count--;
                }
                Thread.Sleep(1);
            }
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Counter counter = new Counter();    

            Thread incThread = new Thread(new ThreadStart(counter.Increase));
            Thread decThread = new Thread(new ThreadStart(counter.Decrease));

            incThread.Start();
            decThread.Start();  

            incThread.Join();
            decThread.Join();

            Console.WriteLine(counter.Count);
        }
    }
}
Output

0

Monitor ํด๋ž˜์Šค๋กœ ๋™๊ธฐํ™”ํ•˜๊ธฐ

  • Monitor ํด๋ž˜์Šค๋Š” ์Šค๋ ˆ๋“œ ๋™๊ธฐํ™”์— ์‚ฌ์šฉํ•˜๋Š” ๋ช‡๊ฐ€์ง€ ์ •์  ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณต
  • ๊ฐ€์žฅ ๋จผ์ € ํ™•์ธํ•  ๋ฉ”์†Œ๋“œ๋Š” Monitor.Enter()์™€ Monitor.Exit() => ์ด ๋‘ ๋ฉ”์†Œ๋“œ๋Š” lock ํ‚ค์›Œ๋“œ์™€ ์™„์ „ํžˆ ๋˜‘๊ฐ™์€ ๊ธฐ๋Šฅ
  • Monitor.Enter() => ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜์„ ๋งŒ๋“ฌ
  • Monitor.Exit() => ํฌ๋ฆฌํ‹ฐ์ปฌ ์„น์…˜์„ ์ œ๊ฑฐ

lock ํ‚ค์›Œ๋“œ์™€ Monitor.Enter() & Monitor.Exit() ๋น„๊ต
lock ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ ๊ฒฝ์šฐ

public void Increase()
{
    int loopCount = 1000;
    while(loopCount-- > 0)
    {
        lock (thisLock){
            count++
        }
    }
}
Monitor ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ ๊ฒฝ์šฐ

public void Increase()
{
    int loopCount = 1000;
    while(loopCount-- > 0)
    {
        Monitor.Enter(thisLock);
        try
        {
            count++;
        }
        finally
        {
            Monitor.Exit(thisLock);
        }
    }
}

  • ๊ฑฐ์˜ ๋น„์Šทํ•œ ํ˜•ํƒœ๋ฅผ ํ•˜๊ณ  ์žˆ๋‹ค.
  • lock ํ‚ค์›Œ๋“œ๋Š” Monitor.Enter() ์™€ Monitor.Exit()๋ฉ”์†Œ๋“œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ Monitor.Enter() ์™€ Monitor.Exit() ์„ ์ด์šฉํ•ด ๋™๊ธฐํ™”๋ฅผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค๋ฉด ์ฐจ๋ผ๋ฆฌ lock ํ‚ค์›Œ๋“œ๋กœ ๋™๊ธฐํ™”๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด ํ”„๋กœ๊ทธ๋žจ ๋ฒ„๊ทธ๋ฉด ํ˜น์€ ์ฝ”๋“œ ์ž‘์„ฑ๋ฉด์—์„œ ๋” ํŽธ๋ฆฌํ•˜๋‹ค.

Monitor.Enter() & Monitor.Exit() ์‚ฌ์šฉ์˜ˆ์ œ ์ฝ”๋“œ
using System;
using System.Threading;

namespace SynchronizeUsingMonitor
{
    class Counter
    {
        const int LOOP_COUNT = 1000;

        readonly object thisLock;

        private int count;
        public int Count
        {
            get { return count; }
        }

        public Counter()
        {
            thisLock = new object();
            count = 0;
        }

        public void Increase()
        {
            int loopCount = LOOP_COUNT;
            while (loopCount-- > 0)
            {
                Monitor.Enter(thisLock);
                try
                {
                    count++;
                }
                finally
                {
                    Monitor.Exit(thisLock);
                }
                Thread.Sleep(1);
            }
        }

        public void Decrease()
        {
            int loopCount = LOOP_COUNT;
            while (loopCount-- > 0)
            {
                Monitor.Enter(thisLock);
                try
                {
                    count--;
                }
                finally
                {
                    Monitor.Exit(thisLock);
                }
                Thread.Sleep(1);
            }
        }

        class MainApp
        {
            static void Main(string[] args)
            {
                Counter counter = new Counter();

                Thread incThread = new Thread(new ThreadStart(counter.Increase));
                Thread decThread = new Thread(new ThreadStart(counter.Decrease));

                incThread.Start();
                decThread.Start();

                incThread.Join();
                decThread.Join();

                Console.WriteLine(counter.Count);
            }
        }
    }
}
Output

0
  • ์ฐธ๊ณ ๋กœ ์˜ˆ์ œ์ฝ”๋“œ๋Š” count ๊ฐ’์ด 1000๋ฒˆ 1์ฆ๊ฐ€ 1000๋ฒˆ 1๊ฐ์†Œํ•˜๋Š” ์ฝ”๋“œ์ž„

Monitor.Wait()๊ณผ Monitor.Pulse()๋กœ ํ•˜๋Š” ์ €์ˆ˜์ค€ ๋™๊ธฐํ™”

  • Monitor.Wait()๊ณผ Monitor.Pulse() ๋Š” ๋‹จ์ˆœํžˆ lock ํ‚ค์›Œ๋“œ๋งŒ์„ ์‚ฌ์šฉํ•  ๋•Œ๋ณด๋‹ค ๋” ์„ฌ์„ธํ•˜๊ฒŒ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๊ฐ„์˜ ๋™๊ธฐํ™”๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.

  • ๋‹จ, ํ•ด๋‹น ๋‘ ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ lock ๋ธ”๋ก ๋‚ด๋ถ€์—์„œ๋งŒ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค. ๋งŒ์ผ lock์„ ๊ฑธ์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋‘ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด CLR์ด SynchronizaionLockException ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

  • Wait ๋ฉ”์†Œ๋“œ๋Š” ์Šค๋ ˆ๋“œ๋ฅผ WaitSleepJoin ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ์ด๋ ‡๊ฒŒ WaitSleepJoin ์ƒํƒœ์— ๋“ค์–ด๊ฐ„ ์Šค๋ ˆ๋“œ๋Š” ๋™๊ธฐํ™”๋ฅผ ์œ„ํ•ด ๊ฐ€์ง€๊ณ  ์žˆ๋˜ lock์„ ๋‚ด๋ ค๋†“์€ ๋’ค Waiting Queue๋ผ๊ณ  ํ•˜๋Š” ํ์— ์ž…๋ ฅ๋˜๊ณ , ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ lock์„ ์–ป์–ด ์ž‘์—…ํ•จ. ์ดํ›„ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ๋งˆ์นœ ๋’ค Pulse๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด CLR์€ Waiting Queue์˜ ๊ฐ€์žฅ ์ฒซ ์š”์†Œ ์Šค๋ ˆ๋“œ๋ฅผ ๊บผ๋‚ธ ๋’ค Ready Queue์— ์ž…๋ ฅํ•จ. Ready Queue์— ์ž…๋ ฅ๋œ ์Šค๋ ˆ๋“œ๋Š” ์ž…๋ ฅ๋œ ์ฐจ๋ก€์— ๋”ฐ๋ผ lock์„ ์–ป์–ด Running ์ƒํƒœ์— ๋“ค์–ด๊ฐ. => ์ฆ‰, ๋‹ค์‹œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ๋ง.


Wait๊ณผ Pulse ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ผ์–ด๋‚˜๋Š” ์ผ

Wait๊ณผ Pulse ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ผ์–ด๋‚˜๋Š” ์ผ

  • ํ•œํŽธ, ThreaSleep() ๋ฉ”์†Œ๋“œ๋„ ์Šค๋ ˆ๋“œ๋ฅผ WaitSleepJoin ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ธฐ๋Š” ํ•˜์ง€๋งŒ Monitor.Pulse() ๋ฉ”์†Œ๋“œ์— ์˜ํ•ด ๊นจ์–ด๋‚  ์ˆ˜ ์—†๋‹ค.(Waiting Queue์— ๋“ค์–ด๊ฐ€์ง€๋„ ์•Š๊ณ .. ใ…‡ใ…‡) ๋‹ค์‹œ Running ์ƒํƒœ๋กœ ๋Œ์•„์˜ค๋ ค๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ž…๋ ฅ๋œ ์‹œ๊ฐ„์ด ๊ฒฝ๊ณผ๋˜๊ฑฐ๋‚˜ Interrupt() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์— ์˜ํ•ด ์ธํ„ฐ๋ŸฝํŠธ ์˜ˆ์™ธ๋ฅผ ๋ฐ›์•„์•ผ ๊นจ์–ด๋‚œ๋‹ค.
  • ๋ฐ˜๋ฉด์— Monitor.Wait() ๋ฉ”์†Œ๋“œ๋Š” Monitore.Pulse() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ๋ฐ”๋กœ ๊นจ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ์ด์œ  ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅํ–ฅ์ƒ์„ ์œ„ํ•ด์„œ Monitor.Wait() ๊ณผ Monitor.Pulse()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

Wait(), Pulse() ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ ์˜ˆ์ œ ์ฝ”๋“œ

using System;
using System.Threading;

namespace WaitPulse
{
    class Counter
    {
        const int LOOP_COUNT = 1000;

        readonly object thisLock;
        bool lockedCount = false;

        private int count;
        public int Count
        {
            get { return count; }
        }

        public Counter()
        {
            thisLock = new object();
            count = 0;
        }

        public void Increase()
        {
            int loopCount = LOOP_COUNT;
            while(loopCount-- > 0)
            {
                lock (thisLock)
                {
                    while(count > 0 || lockedCount == true)
                    {
                        Monitor.Wait(thisLock);
                    }

                    lockedCount = true;
                    count++;
                    lockedCount = false;

                    Monitor.Pulse(thisLock);
                }
            }
        }

        public void Decrease()
        {
            int loopCount = LOOP_COUNT;
            while (loopCount-- > 0)
            {
                lock (thisLock)
                {
                    while (count < 0 || lockedCount == true)
                    {
                        Monitor.Wait(thisLock);
                    }

                    lockedCount = true;
                    count--;
                    lockedCount = false;

                    Monitor.Pulse(thisLock);
                }
            }
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Counter counter = new Counter();

            Thread incThread = new Thread(new ThreadStart(counter.Increase));
            Thread decThread = new Thread(new ThreadStart(counter.Decrease));

            incThread.Start();
            decThread.Start();

            incThread.Join();
            decThread.Join();   

            Console.WriteLine(counter.Count);

        }
    }
}
Output

0
  • Thread.Join() : Join() ๋ฉ”์„œ๋“œ๋Š” ํ˜„์žฌ ์Šค๋ ˆ๋“œ์—์„œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์˜ ์‹คํ–‰์ด ๋๋‚˜๊ธธ ๊ธฐ๋‹ค๋ฆด ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. => ์œ„์˜ ์ฝ”๋“œ์—์„œ๋Š” Main๋ฉ”์„œ๋“œ์—์„œ ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ์— Join๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ ๋‘๊ฐœ์˜ ์Šค๋ ˆ๋“œ์˜ ์ข…๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
  • incThread ๋ฐ decThread ๋‘๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ๊ธฐ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉฐ ์‹คํ–‰ํ•˜๋Š” ์˜ˆ์ œ ๋”ฐ๋ผ์„œ 0์ด ์ถœ๋ ฅ๋จ. => ์ดํ•ด์•ˆ๋˜๋ฉด ๋‹ค์‹œ ์ฝ”๋“œ ์ฒœ์ฒœํžˆ ๋”ฐ๋ผ๊ฐ€๋ณด์ž

Task์™€ Task<TResult>, ๊ทธ๋ฆฌ๊ณ  Parallel


๋ณ‘๋ ฌ์ฒ˜๋ฆฌ์™€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์˜ ์ฐจ์ด

  • ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์™€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ๋น„์Šทํ•œ ์šฉ์–ด ๊ฐ™์ง€๋งŒ ๋‹ค๋ฅธ ๋œป์ด๋‹ค. ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์—ฌ๋Ÿฌ ์ž‘์—…์ž๊ฐ€ ๋‚˜๋ˆ ์„œ ์ˆ˜ํ–‰ํ•œ ๋’ค ๋‹ค์‹œ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ผ ํ•˜๊ณ , ์ด์— ๋น„ํ•ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ์ž‘์—… A๋ฅผ ์‹œ์ž‘ํ•œ ํ›„ A์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ๋งˆ๋ƒฅ ๋Œ€๊ธฐํ•˜๋Š” ๋Œ€์‹  ๊ณง์ด์–ด ๋‹ค๋ฅธ ์ž‘์—… B, C, D .. ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋‹ค๊ฐ€ ์ž‘์—… A๊ฐ€ ๋๋‚˜๋ฉด ๊ทธ ๋•Œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„๋‚ด๋Š” ์ฒ˜๋ฆฌ๋ฐฉ์‹์„ ๋งํ•œ๋‹ค.

System.Threading.Tasks vs Thread ํด๋ž˜์Šค

  • System.Threading.Tasks ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ํด๋ž˜์Šค๋“ค์€ ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ชผ๊ฐ  ๋’ค ์ชผ๊ฐœ์ง„ ์ž‘์—…๋“ค์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ์™€ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์œ„ํ•ด ์„ค๊ณ„๋˜์—ˆ๋‹ค. ๋ฐ˜๋ฉด์— Thread ํด๋ž˜์Šค๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—…์„ (๋‚˜๋ˆ„์ง€ ์•Š๊ณ ) ๊ฐ๊ฐ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ์— ์ ํ•ฉํ•˜๋‹ค. Thread ํด๋ž˜์Šค๋กœ๋„ ํ•˜๋‚˜์˜ ์ž‘์—…์„ ์ชผ๊ฐœ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ์™€ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ (Task๋“ฑ์˜ ํด๋ž˜์Šค๋“ค๋„ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” Thread๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„๋˜์—ˆ์Œ), System.Threading.Tasks์˜ ํด๋ž˜์Šค๋“ค์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ํ›จ์”ฌ ํž˜๋“ค๋‹ค.

System.Threading.Tasks.Task ํด๋ž˜์Šค

  • System.Threading.Tasks.Task ํด๋ž˜์Šค๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์†์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์คŒ
  • ๋™๊ธฐ์ฝ”๋“œ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค์— ์ด ๋ฉ”์†Œ๋“œ์˜ ์‹คํ–‰์ด ์™„์ „ํžˆ ์ข…๋ฃŒ๋˜์–ด์•ผ๋งŒ ๋‹ค์Œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋น„๋™๊ธฐ์ฝ”๋“œ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค์— ๋ฉ”์†Œ๋“œ์˜ ์ข…๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  • ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” ๋‹ค์Œ ์ ˆ์—์„œ async ํ•œ์ •์ž์™€ await ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Task ํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ Action ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ๋„˜๊ฒจ๋ฐ›๋Š”๋‹ค. => ๋ฐ˜ํ™˜ํ˜•์„ ๊ฐ–์ง€ ์•Š๋Š” ๋ฉ”์†Œ๋“œ์™€ ์ต๋ช…๋ฉ”์†Œ๋“œ, ๋ฌด๋ช…ํ•จ์ˆ˜๋“ฑ์„ ๋„˜๊ฒจ๋ฐ›๋Š” ๊ฒƒ

System.Threading.Tasks.Task ํด๋ž˜์Šค ์‚ฌ์šฉ ์˜ˆ์ œ ์ฝ”๋“œ
  • ๋ณต์‚ฌํ•˜๋ ค ํ–ˆ๋˜ ํŒŒ์ผ๋“ค์ด ์กด์žฌํ•˜๋ฉด ์ง€์›Œ์ฃผ๊ณ  ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ ์ถ”๊ฐ€ํ•˜๊ธฐ
  • ์ฑ…์—์„œ ๋‚˜์˜จ ๋™์ž‘์ฒ˜๋Ÿผ ์ถœ๋ ฅํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ๋งŒ์ ธ๋ณด๊ธฐ
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace UsingTask
{
    class MainApp
    {
        static void Main(string[] args)
        {
            string srcFile = args[0];

            Action<object> FileCopyAction = (object state) =>
            {
                String[] paths = (String[])state;
                File.Copy(paths[0], paths[1]);

                Console.WriteLine("TaskID : {0}, ThreadID : {1}, {2} was copied to {3}",
                 Task.CurrentId, Thread.CurrentThread.ManagedThreadId, paths[0], paths[1]);
            };

            Task t1 = new Task(FileCopyAction, new string[] { srcFile, srcFile + ".copy1" });
            // Task() ์ƒ์„ฑ์ž์˜ ๋‘๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ฒซ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜(Action ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ or ์ต๋ช… ๋ฉ”์†Œ๋“œ or ๋ฌด๋ช…ํ•จ์ˆ˜) ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉ๋จ

            Task t2 = Task.Run(() =>
            {
                FileCopyAction(new string[] { srcFile, srcFile + ".copy2" });
            });
            t2.Wait();

            t1.Start();
            t1.Wait();

            Task t3 = new Task(FileCopyAction, new string[] { srcFile, srcFile + ".copy3" });
            t3.RunSynchronously();
            t3.Wait();
        }
    }
}
Output

C:\Users\shkim\source\repos\ClassEx\practice1>dotnet run c:\test\a.txt
TaskID : 1, ThreadID : 4, c:\test\a.txt was copied to c:\test\a.txt.copy2
TaskID : 2, ThreadID : 6, c:\test\a.txt was copied to c:\test\a.txt.copy1
TaskID : 3, ThreadID : 1, c:\test\a.txt was copied to c:\test\a.txt.copy3

UsingTask ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€

  • ๊ต์žฌ์— ์ œ์‹œ๋œ ์ฝ”๋“œ์™€๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. ๊ต์žฌ์—์„œ๋Š” ๋งˆ์ง€๋ง‰์— Wait()ํ•จ์ˆ˜๋“ค์„ ํ•œ๋ฒˆ์— ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์—†๋‹ค. => ๊ฐ™์€ ํŒŒ์ผ์— ๋Œ€ํ•ด ๊ณ„์†ํ•ด์„œ ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹น์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ˆœ์„œ๊ฐ€ ๋’ค์ฃฝ๋ฐ•์ฃฝ์ด ๋œ๋‹ค.
  • ๋”ฐ๋ผ์„œ ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰ํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋’ค์— Wait() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ์ˆœ์„œ๊ฐ€ ์„ž์ด์ง€ ์•Š๋„๋ก ํ•ด์ค€๋‹ค.

Thread.Join() ๊ณผ Task.Wait()
  • Thread.Join() => ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋ ค๋ฉด Join ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด ์Šค๋ ˆ๋“œ t1์ด t2.join()์„ ์‹คํ–‰ํ•˜๋ฉด t1์€ t2๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  • Task.Wait() => Task์˜ ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.

Task<TResult> ํด๋ž˜์Šค => ์ฝ”๋“œ์˜ ๋น„๋™๊ธฐ ์‹คํ–‰๊ฒฐ๊ณผ๋ฅผ ์ฃผ๋Š” ํด๋ž˜์Šค

  • Task\<TResult> ํด๋ž˜์Šค์™€ ๋‹ฌ๋ฆฌ Task ํด๋ž˜์Šค๋Š” Action ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋Š” ์•Š์•˜๋‹ค. ์ด์™€ ๋‹ฌ๋ฆฌ Task\<TResult> ๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ ํ•œ๋ฒˆ ์•Œ์•„๋ณด์ž
  • Task\<TResult> ํด๋ž˜์Šค๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Func ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ๋ฐ›๋Š”๋‹ค.

Taks<TResult> ํด๋ž˜์Šค ์‚ฌ์šฉ ์˜ˆ์ œ ์ฝ”๋“œ
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TaskResult
{
    class MainApp
    {
        static bool IsPrime(long number)
        {
            if (number < 2)
            {
                return false;
            }

            if (number % 2 == 0 && number != 2)
            {
                return false;
            }

            for (long i = 2; i < number; i++)
            {
                if (number % i == 0)
                {
                    return false;
                }
            }

            return true;
        }

        static void Main(string[] args)
        {
            long from = Convert.ToInt64(args[0]);
            long to = Convert.ToInt64(args[1]);
            int taskCount = Convert.ToInt32(args[2]);

            Func<object , List<long>> FindPrimeFunc = (objRange) =>
            {
                long[] range = (long[])objRange;
                List<long> found = new List<long>();

                for(long i = range[0]; i < range[1]; i++)
                {
                    if (IsPrime(i))
                    {
                        found.Add(i);
                    }
                }
                return found;
            };

            Task<List<long>>[] tasks = new Task<List<long>>[taskCount];
            long currentFrom = from;
            long currentTo = to / tasks.Length;

            for (int i = 0; i < tasks.Length; i++)
            {
                Console.WriteLine("Task[{0}] : {1} ~ {2}", i, currentFrom, currentTo);

                tasks[i] = new Task<List<long>>(FindPrimeFunc, new long[] { currentFrom, currentTo });
                currentFrom = currentTo + 1;

                if(i == tasks.Length - 2)
                {
                    currentTo = to;
                }
                else
                {
                    currentTo = currentTo + (to / tasks.Length);
                }
            }

            Console.WriteLine("Please press enter to start ... ");
            Console.ReadLine();
            Console.WriteLine("Started ...");

            DateTime startTime = DateTime.Now;

            foreach (Task<List<long>> task in tasks)
            {
                task.Start();
            }

            List<long> total = new List<long>();


            foreach (Task<List<long>> task in tasks)
            {
                task.Wait();
                total.AddRange(task.Result.ToArray());
            }

            DateTime endTime = DateTime.Now;

            TimeSpan ellapsed = endTime - startTime;

            Console.WriteLine("Prime number count between {0} and {1} : {2}", from, to, total.Count);

            Console.WriteLine("Ellapsed time : {0}",ellapsed);
        }
    }
}
Output 1st

C:\Users\shkim\source\repos\ClassEx\practice1>dotnet run 0 100000 1
Task[0] : 0 ~ 100000
Please press enter to start ...

Started ...
Prime number count between 0 and 100000 : 9592
Ellapsed time : 00:00:03.9273830

Ouput 2nd

C:\Users\shkim\source\repos\ClassEx\practice1>dotnet run 0 100000 5
Task[0] : 0 ~ 20000
Task[1] : 20001 ~ 40000
Task[2] : 40001 ~ 60000
Task[3] : 60001 ~ 80000
Task[4] : 80001 ~ 100000
Please press enter to start ...

Started ...
Prime number count between 0 and 100000 : 9592
Ellapsed time : 00:00:01.3796182
  • ๊ฐ๊ฐ์˜ Task ๋ณ„๋กœ ์†Œ์ˆ˜๋ฅผ ํƒ์ƒ‰ํ•  ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•ด์ฃผ๋ฉฐ ํ•ด๋‹น ๋ฒ”์œ„๋‚ด์—์„œ ์†Œ์ˆ˜์˜ ๊ฐฏ์ˆ˜๋ฅผ ๊ตฌํ•œ๋‹ค.

  • ์ž…๋ ฅ : ์‹œ์ž‘ ์ˆซ์ž, ๋ ์ˆซ์ž, ๋ฒ”์œ„๋ฅผ ๋ช‡๊ฐœ๋กœ ๋‚˜๋ˆŒ ๊ฒƒ์ธ์ง€


Parallel ํด๋ž˜์Šค => ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๋ฅผ ์‰ฝ๊ฒŒ ํ•˜๋Š”๋ฐ์— ๋„์›€์„ ์ฃผ๋Š” ํด๋ž˜์Šค

  • ์ด์ „ Task\<TResult> ํด๋ž˜์Šค์˜ ์˜ˆ์ œ์—์„œ๋Š” ํŠน์ • ๋ฒ”์œ„ ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ์†Œ์ˆ˜๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ Task ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ฐ ์ธ์Šคํ„ด์Šค์—๊ฒŒ ์ž‘์—…ํ•  ๋ฒ”์œ„๋ฅผ ํ• ๋‹นํ•œ ํ›„, foreach ๋ฌธ์„ ์ด์šฉํ•ด ์‹œ๋™์„ ๊ฑธ์—ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์‹œ๋™์ด ๊ฑธ๋ฆฐ Task ๊ฐ์ฒด๋“ค์€ ๋™์‹œ์— ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ ๋’ค ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค.

  • MicroSoft์—์„œ๋Š” ์ด์™€ ๊ฐ™์ด Task\<TResult>๋ฅผ ์ด์šฉํ•ด์„œ ์ง์ ‘ ๊ตฌํ˜„ํ–ˆ๋˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ Parallel ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•ด์„œ ๋” ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

  • Parallel ํด๋ž˜์Šค๊ฐ€ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ์— ๋ช‡ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ œ๊ณตํ• ์ง€๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํŒ๋‹จํ•˜์—ฌ ์ตœ์ ํ™”ํ•œ๋‹ค. => ์‚ฌ์šฉ์ž๊ฐ€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•„๋„ ๋˜๋Š”๋“ฏ...?


Parallel ํด๋ž˜์Šค ์‚ฌ์šฉ ์˜ˆ์ œ ์ฝ”๋“œ

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ParallelLoop
{
    class MainApp
    {
        static bool IsPrime(long number)
        {
            if (number < 2)
            {
                return false;
            }
            if (number % 2 == 0 && number != 2)
            {
                return false;
            }

            for (long i = 2; i < number; i++)
            {
                if (number % i == 0)
                {
                    return false;
                }
            }

            return true;
        }

        static void Main(string[] args)
        {
            long from = Convert.ToInt64(args[0]);
            long to = Convert.ToInt64(args[1]);

            Console.WriteLine("Please press enter to start ... ");
            Console.ReadLine();
            Console.WriteLine("Started ... ");

            DateTime startTime = DateTime.Now;

            object thisLock = new object();
            // readonly ์™€ const์˜ ์ฐจ์ด
            // ์ฐธ์กฐ๋ณ€์ˆ˜, ๋‚ด๋ถ€ ๊ฐ‘ํ˜•์‹ ํ˜น์€ ์ฐธ์กฐ ํ˜•์‹์— ๋”ฐ๋ฅธ ์‚ฌ์šฉ์ฐจ์ด
            // dll ๋‚ด๋ถ€์—์„œ ์œ„ ๋‘ ํ‚ค์›Œ๋“œ๋ฅผ ์จ์„œ ... ์•„๋ฌดํŠผ ๊ถ๊ธˆํ•ดํ•ด๋ณด๊ธฐ 
            // static์œผ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์— lock๊ฑธ๋•Œ๋Š” ์–ด๋–ป๊ฒŒํ• ๊นŒ์š”??
            List<long> total = new List<long>();

            Parallel.For(from, to, (long i) =>
            {
                if (IsPrime(i))
                {
                    lock (total) 
                    // critical section ์ œ์–ด
                    // lock ๊ฑธ๋•Œ๋Š” ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด ๊ฑธ ์ˆ˜ ์žˆ๋‹ค.
                    {
                        total.Add(i);
                    }
                }
            });

            DateTime endTime = DateTime.Now;

            TimeSpan ellapsed = endTime - startTime;

            Console.WriteLine("Prime number count between {0} and {1} : {2} ", from, to, total.Count);
            Console.WriteLine("Prime number count between" + from + " and " + to + " : " + total.Count);
            Console.WriteLine($"Prime number count between{from} and {to} : {total.Count}");

            Console.WriteLine("Ellapsed time : {0}", ellapsed);
        }
    }
}
Output

C:\Users\shkim\source\repos\ClassEx\practice1>dotnet run 0 100000
Please press enter to start ...

Started ...
Prime number count between 0 and 100000 : 9592
Ellapsed time : 00:00:00.5171736
  • ๊ต์žฌ์—์„œ ์ œ๊ณต๋œ ์ฝ”๋“œ์™€๋Š” ๋‹ค๋ฅด๋‹ค.
  • ํ•ด๋‹น total ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ๋“ค์ด ์„œ๋กœ ์›์†Œ๋ฅผ Add ํ•จ์œผ๋กœ์จ ํ•ด๋‹น Critical Section์—์„œ ์—๋Ÿฌ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ ์ด๋กœ์ธํ•ด ์‹คํ–‰์‹œ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋‹ค. ๋”ฐ๋ผ์„œ ํ•ด๋‹น total.Add(i) ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๋ถ€๋ถ„์— lock ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์คŒ์œผ๋กœ์จ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์ค‘์œผ๋กœ ํ•ด๋‹น Critical Section์— ์ง„์ž…ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ œ์–ดํ•˜์˜€๋‹ค.
  • lock ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•œ ๋™๊ธฐํ™”
    • lock์„ ๊ฑธ๋•Œ์—๋Š” ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•œ๋‹ค.
    • ๋งŒ์ผ Critical Section์— ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ํ•ด๋‹น ์ฐธ์กฐ๋ณ€์ˆ˜๋ฅผ lockํ‚ค์›Œ๋“œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. => ํ•ด๋‹น Critical Section์— ๋งˆ๋•…ํ•œ ์ฐธ์กฐ๋ณ€์ˆ˜๊ฐ€ ์—†๊ฑฐ๋‚˜ ์ฐธ์กฐ๋ณ€์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„ ์–ด๋–ค๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผํ• ์ง€ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ๋Š” ๊ต์žฌ์ฒ˜๋Ÿผ object thisLock = new object()์ฒ˜๋Ÿผ ์„ ์–ธํ•ด์„œ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.
  • readonly ํ‚ค์›Œ๋“œ ์งˆ๋ฌธ
    • readonly ํ‚ค์›Œ๋“œ์™€ const์˜ ์ฐจ์ด
    • dll์„ ๋ฐฐํฌ์‹œ ์–ด๋–ค๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ์ˆ˜์ •ํ–ˆ๋А๋ƒ์— ๋”ฐ๋ผ ์ „์ฒด๋ฅผ ๋นŒ๋“œํ•˜๊ฑฐ๋‚˜ ๋ถ€๋ถ„๋งŒ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค ๊ฒƒ์ด ์ด๋Ÿด๊นŒ??(readonly ํ˜น์€ const๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜ ์ค‘ ํ•˜๋‚˜)
    • static ์œผ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์— lock์„ ๊ฑธ๋• ์–ด๋–ป๊ฒŒ ํ• ๊นŒ?

async ํ•œ์ •์ž์™€ await ์—ฐ์‚ฐ์ž๋กœ ๋งŒ๋“œ๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ

  • async ํ•œ์ •์ž
    public static async Task MyMethodAsync()
    {
      ...
    }
  • ์ด๋ ‡๊ฒŒ async ํ•œ์ •์ž๋กœ ๋ฉ”์†Œ๋“œ๋‚˜ ํƒœ์Šคํฌ๋ฅผ ์ˆ˜์‹ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.
  • ๋‹ค๋งŒ async๋กœ ํ•œ์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜ํ™˜ํ˜•์‹์ด Task๋‚˜ Task\<TResult>, ๋˜๋Š” void ์—ฌ์•ผ๋งŒ ํ•œ๋‹ค.
  • ์‹คํ–‰ํ•˜๊ณ  ์žŠ์–ด๋ฒ„๋ฆด ์ž‘์—…์„ ๋‹ด๊ณ  ์žˆ๋Š” ๋ฉ”์†Œ๋“œ๋ผ๋ฉด ๋ฐ˜ํ™˜ ํ˜•์‹์„ void ๋กœ ์„ ์–ธํ•˜๊ณ , ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฉ”์†Œ๋“œ๋ผ๋ฉด Task, Task\<TResult> ๋กœ ์„ ์–ธํ•˜๋ฉด ๋œ๋‹ค.
  • async๋กœ ์„ ์–ธํ•œ void ํ˜•์‹์˜ ๋ฉ”์†Œ๋“œ๋Š” ํ˜ธ์ถœ ์ฆ‰์‹œ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ œ์–ด๋ฅผ ๋Œ๋ ค์ค€๋‹ค. => void ๋ฉ”์†Œ๋“œ๋Š” async ํ‚ค์›Œ๋“œ ํ•˜๋‚˜๋งŒ์œผ๋กœ ์™„์ „ํ•œ ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ๋˜๋Š” ๊ฒƒ
  • ํ•˜์ง€๋งŒ Task, Task\<TResult> ํ˜•์‹์˜ ๋ฉ”์†Œ๋“œ๋Š” async ๋กœ ์ˆ˜์‹ํ•˜๊ธฐ๋งŒ ํ•ด์„œ๋Š” ๋ณดํ†ต์˜ ๋™๊ธฐ ์ฝ”๋“œ์™€ ๋‹ค๋ฆ„์—†์ด ๋™์ž‘ํ•œ๋‹ค.
  • C# ์ปดํŒŒ์ผ๋Ÿฌ๋Š” Task, Task\<TResult> ํ˜•์‹์˜ ๋ฉ”์†Œ๋“œ๋ฅผ async ํ•œ์ •์ž๊ฐ€ ์ˆ˜์‹ํ•˜๋Š” ๊ฒฝ์šฐ, await ์—ฐ์‚ฐ์ž๊ฐ€ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์˜ ์–ด๋””์— ์œ„์น˜ํ•˜๋Š”์ง€๋ฅผ ์ฐพ๋Š”๋‹ค. ์ดํ›„ await ์—ฐ์‚ฐ์ž๋ฅผ ์ฐพ์œผ๋ฉด ๊ทธ๊ณณ์—์„œ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ œ์–ด๋ฅผ ๋Œ๋ ค์ฃผ๋„๋ก ์‹คํ–‰ ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค. => ๋งŒ์ผ await ์—ฐ์‚ฐ์ž๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค๋ฉด ํ˜ธ์ถœ์ž์—๊ฒŒ ์ œ์–ด๋ฅผ ๋Œ๋ ค์ฃผ์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฉ”์†Œ๋“œ/ํƒœ์Šคํฌ๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.
1. async ๋กœ ํ•œ์ •ํ•œ void ํ˜•์‹ ๋ฉ”์†Œ๋“œ๋Š” await ์—ฐ์‚ฐ์ž๊ฐ€ ์—†์–ด๋„ ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰

2. async ๋กœ ํ•œ์ •ํ•œ Task ๋˜๋Š” Task<TResult> ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ/ํƒœ์Šคํฌ/๋žŒ๋‹ค์‹ ์€ 
   await ์—ฐ์‚ฐ์ž๋ฅผ ๋งŒ๋‚˜๋Š” ๊ณณ์—์„œ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ œ์–ด๋ฅผ ๋Œ๋ ค์ฃผ๋ฉฐ, 
   await ์—ฐ์‚ฐ์ž๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋™๊ธฐ๋กœ ์‹คํ–‰๋œ๋‹ค.

async ํ•œ์ •์ž & await ์—ฐ์‚ฐ์ž๊ฐ€ ์–ด๋–ป๊ฒŒ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ํ˜•์„ฑํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ดํ•ด๋„์›€ ์ด๋ฏธ์ง€

[async ํ•œ์ •์ž & await ์—ฐ์‚ฐ์ž๊ฐ€ ์–ด๋–ป๊ฒŒ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ํ˜•์„ฑํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ดํ•ด๋„์›€ ์ด๋ฏธ์ง€]

  • ์œ„ ๊ทธ๋ฆผ์—์„œ Caller() ์˜ ์‹คํ–‰์ด ์‹œ์ž‘๋˜๋ฉด โ‘  ์˜ ํ๋ฆ„์„ ๋”ฐ๋ผ ๋ฌธ์žฅ1์ด ์‹คํ–‰๋˜๊ณ , ์ด์–ด์„œ โ‘ก ์˜ ํ๋ฆ„์„ ๋”ฐ๋ผ MyMethodAsync() ๋ฉ”์†Œ๋“œ์˜ ์‹คํ–‰์œผ๋กœ ์ œ์–ด๊ฐ€ ์ด๋™
  • MyMethodAsync() ์—์„œ๋Š” โ‘ข ์„ ๋”ฐ๋ผ ๋ฌธ์žฅ2๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๋‚˜๋ฉด async ๋žŒ๋‹ค๋ฌธ์„ ํ”ผ์—ฐ์‚ฐ์ž๋กœ ํ•˜๋Š” await ์—ฐ์‚ฐ์ž๋ฅผ ๋งŒ๋‚˜๊ฒŒ๋จ.
  • ๋ฐ”๋กœ ์—ฌ๊ธฐ์—์„œ CLR ์€ โ‘ฃ ๋ฅผ ๋”ฐ๋ผ ์ œ์–ด๋ฅผ ํ˜ธ์ถœ์ž์ธ Caller() ์—๊ฒŒ๋กœ ์ด๋™์‹œํ‚ค๊ณ , ์œ„ ๊ทธ๋ฆผ์—์„œ ์ ์„ ์œผ๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š” โ“ ์™€ โ“‘ ์˜ ํ๋ฆ„์„ ๋™์‹œ์— ์‹คํ–‰ํ•˜๊ฒŒ ๋จ

async ํ•œ์ •์ž์™€ await ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ ์˜ˆ์ œ ์ฝ”๋“œ

using System;
using System.Threading.Tasks;

namespace Async
{
    class MainApp
    {
        async static private void MyMethodAsync (int count)
        {
            Console.WriteLine("C"); // 3
            Console.WriteLine("D"); // 4 

            await Task.Run(async () =>
            {
                for (int i = 0; i <= count; i++)
                {
                    Console.WriteLine("{0}/{1} ... ", i, count); // 5, 6, 7 ,8
                    await Task.Delay(100);
                }
            });

            Console.WriteLine("G"); // 11
            Console.WriteLine("H"); // 12
        }

        static void Caller()
        {
            Console.WriteLine("A"); // 1
            Console.WriteLine("B"); // 2

            MyMethodAsync(3); 

            Console.WriteLine("E"); // 9
            Console.WriteLine("F"); // 10
            // => 5,6,7,8 ๊ณผ 9,10 ๋Š” ๊ฑฐ์˜ ๋™์‹œ์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์ œ์–ด์— ์˜ํ•ด ์‹คํ–‰๋จ 
            // => ์ด๋“ค 6๋ฒˆ์˜ ์ถœ๋ ฅ์€ ์ˆœ์„œ๊ฐ€ ์„ž์ด๊ฑฐ๋‚˜ ๋’ค๋ฐ”๋€” ์ˆ˜ ๋„ ์žˆ์Œ 
            // => ๋™์‹œ์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ
        }

        static void Main(string[] args)
        {
            Caller();

            Console.ReadLine();
            // ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ๋ฐฉ์ง€
        }
    }
}
Output - ์ฒซ๋ฒˆ์งธ ์‹œ๋„

A
B
C
D
0/3 ...
E
F
1/3 ...
2/3 ...
3/3 ...
G
H

Output - ๋‘๋ฒˆ์งธ ์‹œ๋„

A
B
C
D
E
F
0/3 ...
1/3 ...
2/3 ...
3/3 ...
G
H
  • 5,6,7,8 ๊ณผ 9,10 ๋Š” ๊ฑฐ์˜ ๋™์‹œ์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์ œ์–ด์— ์˜ํ•ด ์‹คํ–‰๋จ
  • ์ด๋ ‡๊ฒŒ ์ด 6๊ฐœ์˜ ์ถœ๋ ฅ์€ ์ˆœ์„œ๊ฐ€ ์„ž์ด๊ฑฐ๋‚˜ ๋’ค๋ฐ”๋€” ์ˆ˜ ๋„ ์žˆ์Œ
  • ๋™์‹œ์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ

Task.Delay() ์— ๋Œ€ํ•˜์—ฌ
  • Task.Delay()๊ฐ€ ํ•˜๋Š” ์ผ์€ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์ž…๋ ฅ๋œ ์‹œ๊ฐ„ ํ›„์— Task ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ
  • ์‹ค์งˆ์ ์ธ ์—ญํ• ์€ Thread.Sleep() ๊ณผ ๋™์ผํ•˜๋‚˜ ์ด Task.Delay()์™€ Thread.Sleep()์€ ์ฐจ์ด๊ฐ€ ์žˆ์Œ
  • Task.Delay()๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ๋ธ”๋ก์‹œํ‚ค์ง€ ์•Š์ง€๋งŒ, Thread.Sleep()์€ ์ „์ฒด๋ฅผ ๋ธ”๋ก์‹œํ‚ด
  • UI(User Interface) ์Šค๋ ˆ๋“œ ์•ˆ์—์„œ Thread.Sleep()์„ ํ˜ธ์ถœํ•˜๋ฉด UI๊ฐ€ Sleep()์ด ๋ฐ˜ํ™˜๋˜๊ธฐ๊นŒ์ง€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์‘๋‹ตํ•˜์ง€ ๋ชปํ•˜๊ฒ ์ง€๋งŒ, Task.Delay()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด UI๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž˜ ์‘๋‹ตํ•จ.

.Net ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋น„๋™๊ธฐ API ๋ง›๋ณด๊ธฐ

๋™๊ธฐ ์ฝ”๋“œ

static long CopySync(string FromPath, string ToPath)
        {
            using (var fromStream = new FileStream(FromPath, FileMode.Open))
            {
                long totalCopied = 0;
                using(var toStream = new FileStream(ToPath, FileMode.Create))
                {
                    byte[] buffer = new byte[1024];
                    int nRead = 0;
                    while((nRead = fromStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        toStream.Write(buffer, 0, nRead);
                        totalCopied += nRead;
                    }
                }
                return totalCopied;
            }
        }

๋น„๋™๊ธฐ ์ฝ”๋“œ

async Task<long> CopyAsync(string FromPath, string ToPath)
            // async๋กœ ํ•œ์ •ํ•œ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๋„ ์—ญ์‹œ async๋กœ ํ•œ์ •๋˜์–ด ์žˆ์–ด์•ผํ•จ
            // ๋ฐ˜ํ™˜ ํ˜•์‹์€ Task ๋˜๋Š” void ํ˜•
        {
            using(var fromStream = new FileStream(FromPath, FileMode.Open))
            {
                long totalCopied = 0;

                using(var toStream = new FileStream(ToPath, FileMode.Create))
                {
                    byte[] buffer = new byte[1024];
                    int nRead = 0;
                    while((nRead = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                    // ReadAsync()์™€ WriteAsync() ๋ฉ”์†Œ๋“œ๋Š” .NET ํ”„๋ ˆ์ž„์›Œํฌ์— async๋กœ ํ•œ์ •๋˜์–ด ์žˆ์Œ
                    // ์ด๋“ค์„ ํ˜ธ์ถœํ•˜๋ ค๋ฉด await ์—ฐ์‚ฐ์ž๊ฐ€ ํ•„์š”ํ•จ.
                    {
                        await toStream.WriteAsync(buffer, 0, nRead);
                        totalCopied += nRead;
                    }
                }
                return totalCopied;
            }
        }
  • ์œ„์˜ ๋™๊ธฐ ์ฝ”๋“œ์™€ ๋น„๋™๊ธฐ ์ฝ”๋“œ์— ์„ ์–ธ๋œ ๋ฉ”์†Œ๋“œ ๋‘˜ ์‚ฌ์ด์—๋Š” ์•„๋ฌด๋Ÿฐ ๊ธฐ๋Šฅ์  ์ฐจ์ด๊ฐ€ ์—†๋‹ค.
  • ๋‘˜๋‹ค ๋˜‘๊ฐ™์ด ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜๊ณ , ๋ณต์‚ฌ๋ฅผ ๋งˆ์นœ๋’ค์—๋Š” ํŒŒ์ผ์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ํ•˜์ง€๋งŒ ์ด ๋‘˜์„ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ํ˜ธ์ถœํ•ด๋ณด๋ฉด ํ”„๋กœ๊ทธ๋žจ์˜ ์‘๋‹ต์„ฑ์— ํฐ ์ฐจ์ด๊ฐ€ ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • CopySync() ๋ฉ”์†Œ๋“œ(๋™๊ธฐ ๋ฐฉ์‹)์˜ ๊ฒฝ์šฐ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ผ๋‹จ ํ˜ธ์ถœ๋˜๋ฉด ์‹คํ–‰์ด ์ข…๋ฃŒ๋  ๋–„๊นŒ์ง€ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฑฐ์˜ ์‘๋‹ต์„ ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฐ˜๋ฉด, CopyAsync() ๋ฉ”์†Œ๋“œ(๋น„๋™๊ธฐ ๋ฐฉ์‹)๋Š” ์‹คํ–‰๋˜๋Š” ์ค‘๊ฐ„์—๋„ ์—ฌ์ „ํžˆ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์— ์ ‘๊ทผํ•˜๋Š”๋ฐ ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.
  • ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ด๋ณด์ž

๋น„๋™๊ธฐ API ์‚ฌ์šฉ ์˜ˆ์ œ ์ฝ”๋“œ

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

namespace AsyncFileIO
{
    class MainApp
    {
        // ํŒŒ์ผ ๋ณต์‚ฌ ํ›„ ๋ณต์‚ฌํ•œ ํŒŒ์ผ ์šฉ๋Ÿ‰ ๋ณ€ํ™˜
        static async Task<long> CopyAsync(string FromPath, string ToPath)
        // async๋กœ ํ•œ์ •ํ•œ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๋„ ์—ญ์‹œ async๋กœ ํ•œ์ •๋˜์–ด ์žˆ์–ด์•ผํ•จ
        // ๋ฐ˜ํ™˜ ํ˜•์‹์€ Task ๋˜๋Š” void ํ˜•
        {
            using (var fromStream = new FileStream(FromPath, FileMode.Open))
            {
                long totalCopied = 0;

                using (var toStream = new FileStream(ToPath, FileMode.Create))
                {
                    byte[] buffer = new byte[1024];
                    int nRead = 0;
                    while ((nRead = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                    // ReadAsync()์™€ WriteAsync() ๋ฉ”์†Œ๋“œ๋Š” .NET ํ”„๋ ˆ์ž„์›Œํฌ์— async๋กœ ํ•œ์ •๋˜์–ด ์žˆ์Œ
                    // ์ด๋“ค์„ ํ˜ธ์ถœํ•˜๋ ค๋ฉด await ์—ฐ์‚ฐ์ž๊ฐ€ ํ•„์š”ํ•จ.
                    {
                        await toStream.WriteAsync(buffer, 0, nRead);
                        totalCopied += nRead;
                    }
                }
                return totalCopied;
            }
        }

        static async void DoCopy(string FromPath, string ToPath)
        {// async๋กœ ํ•œ์ •ํ•œ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๋„ ์—ญ์‹œ async๋กœ ํ•œ์ •๋˜์–ด ์žˆ์–ด์•ผํ•จ
        // ๋ฐ˜ํ™˜ ํ˜•์‹์€ Task ๋˜๋Š” void ํ˜•
            long totalCopied = await CopyAsync(FromPath, ToPath);

            Console.WriteLine("Copied Total {0} Bytes.", totalCopied);
        }

        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                Console.WriteLine("Usage : AsyncFileIO <Source> <Destination>");
                return;
            }

            DoCopy(args[0], args[1]);

            Console.ReadLine();
        }
    }
}
Output

C:\Users\shkim\source\repos\ClassEx\practice1>dotnet run aaa.txt bbb.txt
Copied Total 170980 Bytes.

๊ณผ์ œ

[๊ตฌํ˜„๋‚ด์šฉ]

  1. ์ž…๋ ฅ Thread ๋Š” ์ž‘์—… ์ˆœ์„œ์™€ ์ž‘์—… ๋‚ด์šฉ์„ ์ฒ˜๋ฆฌ Thread๋กœ ์ „๋‹ฌํ•˜๊ณ  ์ฒ˜๋ฆฌ Thread๋Š” ์ž‘์—… ์ˆœ์„œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ž‘์—… ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์—ฌ ์ถœ๋ ฅ
  • ์กฐ๊ฑด

    • ์ž…๋ ฅ Thread

      • 2๊ฐœ Thread
      • ๋ฏธ๋ฆฌ ์ •์˜๋œ ํŒŒ์ผ ์„ ์ฝ์–ด์„œ ์ฒ˜๋ฆฌ Thread๋กœ ์ „๋‹ฌ
      • ํŒŒ์ผ์„ ๋‹ค ์ฝ์œผ๋ฉด Thread ์ข…๋ฃŒ
    • ์ฒ˜๋ฆฌ Thread

      • 1๊ฐœ Thread
      • ์ž…๋ ฅ Thread์™€ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  List ์ƒ์„ฑ
      • ์ฒ˜์Œ ์ž‘์—…์ด ์ž…๋ ฅ๋  ๋•Œ ๊นŒ์ง€ ์ฒ˜๋ฆฌ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜์ง€ ์•Š์Œ(์ฒ˜์Œ ์ž‘์—… ๋ฒˆํ˜ธ 0)
      • ๋งˆ์ง€๋ง‰ ์ž‘์—…์ด ์ž…๋ ฅ๋˜๋ฉด Thread ์ข…๋ฃŒ (9๋ฒˆ ์ž‘์—…์ด ์ž…๋ ฅ๋˜๋ฉด ์ข…๋ฃŒ)

๊ตฌํ˜„ ์ฝ”๋“œ

using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ThreadEx
{
    class MainApp
    {
        static List<(string, string)> list = new List<(string, string)>();

        static void Main(string[] args)
        {
            Action<object> readFile = (object obj) =>
            {
                string c = (string)obj;
                StreamReader sr = new StreamReader(new FileStream("c:\\test\\a" + c + ".txt", FileMode.Open));

                while (sr.EndOfStream == false)
                {
                    string str = sr.ReadLine();
                    string[] word = str.Split(',');
                    lock (list)
                    {
                        list.Add((word[0], word[1]));
                    }
                }
                sr.Close();
            };

            Action readList = () =>
            {
                int index = 0;

                while (index < 10)
                {
                    if(list.Count > 0) { 
                        list.Sort();
                        if (index.ToString() == list[0].Item1) {
                            Console.WriteLine($"{list[0].Item1} : {list[0].Item2}");
                            list.RemoveAt(0);
                            index++;
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
            };

            Task t1 = new Task(readFile, "1");

            Task t2 = new Task(readFile, "2");

            Task t3 = new Task(readList);

            t3.Start();
            t1.Start();
            t2.Start();

            t1.Wait();
            t2.Wait();
            t3.Wait();

        }
    }
}
Output

0 : 0๋ฒˆ์ž‘์—…
1 : 1๋ฒˆ์ž‘์—…
2 : 2๋ฒˆ์ž‘์—…
3 : 3๋ฒˆ์ž‘์—…
4 : 4๋ฒˆ์ž‘์—…
5 : 5๋ฒˆ์ž‘์—…
6 : 6๋ฒˆ์ž‘์—…
7 : 7๋ฒˆ์ž‘์—…
8 : 8๋ฒˆ์ž‘์—…
9 : 9๋ฒˆ์ž‘์—…
  • ์œ„์˜ ์ฝ”๋“œ๋Š” 3๊ฐœ์˜ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ํŒŒ์ผ์„ ์ฝ๊ณ  ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•œ๋‹ค.
  • ์Šค๋ ˆ๋“œ์˜ ์‹คํ–‰์ˆœ์„œ๋Š” ์ฒ˜๋ฆฌThread => ์ž…๋ ฅThread1 => ์ž…๋ ฅThread2 ์ด๋‹ค.
  • ์ด๋ ‡๊ฒŒ ์‹คํ–‰์ˆœ์„œ๋ฅผ ์ •์˜ํ•œ ์ด์œ ๋Š” ๋งŒ์ผ ํŒŒ์ผํฌ๊ธฐ๊ฐ€ ๊ต‰์žฅํžˆ ํฌ๊ณ  ์ž…๋ ฅ Thread๊ฐ€ ๋จผ์ € ์‹คํ–‰๋œ๋‹ค๋ฉด ์ฒ˜๋ฆฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ผœ์ง€๋ฉด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ๋  ๋ฆฌ์ŠคํŠธ์˜ ํฌ๊ธฐ๊ฐ€ ๊ต‰์žฅํžˆ ํด ์ˆ˜๋„ ์žˆ์„ ๋ฟ๋”๋Ÿฌ ๋งŒ์ผ List์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ ๋„˜์–ด์„ ๋‹ค๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ๋น„์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. => ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ํ˜„์žฌ ๊ฐœ๋ฐœํ•˜์‹ค ๋•Œ์—๋„ ์ฒ˜๋ฆฌThread๋ฅผ ๋จผ์ € ๋™์ž‘์‹œํ‚จ ํ›„ ์ž…๋ ฅ Thread๋ฅผ ๋™์ž‘์‹œํ‚จ๋‹ค๊ณ  ํ•จ.
  • ์ถ”๊ฐ€๋‚ด์šฉ : ํ•˜๋‚˜์˜ ๊ฐ์ฒด์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ํฌ๊ธฐ => LargeObject๋ฅผ ์ด์šฉํ•ด์„œ ์ดˆ๊ณผํ•  ์ˆ˜ ์žˆ์Œ

'๐Ÿ’ป Programming Language > C#' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

์Šคํ„ฐ๋””) ๋‘๋ฒˆ์งธ ์Šคํ„ฐ๋”” ํ”ผ๋“œ๋ฐฑ ๋ฐ ์งˆ๋ฌธ ์ •๋ฆฌ๋‚ด์šฉ  (0) 2022.04.08
์Šคํ„ฐ๋””) ์ฒซ๋ฒˆ์งธ ์Šคํ„ฐ๋”” ํ”ผ๋“œ๋ฐฑ ๋ฐ ์งˆ๋ฌธ ์ •๋ฆฌ๋‚ด์šฉ  (0) 2022.04.08
42. LINQ ์„ธ๋ถ€ ๋ฌธ๋ฒ•  (0) 2022.04.08
41. ์ต๋ช… Type  (0) 2022.04.08
40. LINQ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•  (0) 2022.04.08
'๐Ÿ’ป Programming Language/C#' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ์Šคํ„ฐ๋””) ๋‘๋ฒˆ์งธ ์Šคํ„ฐ๋”” ํ”ผ๋“œ๋ฐฑ ๋ฐ ์งˆ๋ฌธ ์ •๋ฆฌ๋‚ด์šฉ
  • ์Šคํ„ฐ๋””) ์ฒซ๋ฒˆ์งธ ์Šคํ„ฐ๋”” ํ”ผ๋“œ๋ฐฑ ๋ฐ ์งˆ๋ฌธ ์ •๋ฆฌ๋‚ด์šฉ
  • 42. LINQ ์„ธ๋ถ€ ๋ฌธ๋ฒ•
  • 41. ์ต๋ช… Type
S.Honey
S.Honey
  • S.Honey
    Algo ์“ฐ์ž
    S.Honey
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (123)
      • ํšŒ๊ณ  (0)
        • ์ทจ์—… ํ›„ ํšŒ๊ณ  (0)
      • ๐Ÿƒ Frontend Road-Map (2)
        • ๐Ÿšฉ Summary (1)
        • ๐Ÿ“š Road-Map Contents (1)
        • ๐ŸŸง HTML (0)
        • ๐ŸŸฆ CSS (0)
        • ๐ŸŸจ Javascript (0)
        • โฌœ React (0)
        • ๐ŸŸช Redux (0)
      • Backend (0)
        • QueryDSL (0)
      • ๐Ÿ’ป Programming Language (54)
        • C# (51)
        • Flutter-Dart (3)
        • Java (0)
      • ๐Ÿ“š Computer Science (4)
        • Algorithms (4)
        • Database (0)
        • Network (0)
        • Operating System(OS) (0)
      • ๐Ÿ’ฏ CodingTest (60)
        • BaekJoon (22)
        • Programmers (34)
        • CodeTree (4)
      • โœ’๏ธ Design Pattern (1)
      • ๐Ÿฑ Etc (2)
        • Jenkins Plugin ์ œ์ž‘๊ธฐ (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ๋งํฌ

    • ๊ณต์ง€์‚ฌํ•ญ

      • ๐Ÿ“– ๊ณต๋ถ€ ์ฐธ๊ณ  ๊ต์žฌ ๋ฐ ์ž๋ฃŒ
    • ์ธ๊ธฐ ๊ธ€

    • ํƒœ๊ทธ

      JS
      ์“ฐ์…จ์ž–์•„
      Algorithm
      ์ฝ”๋”ฉํ…Œ์ŠคํŠธ
      ์ฝ”๋“œํŠธ๋ฆฌ
      BFS
      ๊ตฌํ˜„
      ํŒŒ์ด์ฌ
      DP
      ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰
      ๋ฌธ์ž์—ด ํŒŒ์‹ฑ
      ์Šคํ„ฐ๋””
      Flutter
      c#
      ๋ฐฑ์ค€
      ์ž๋ฃŒ๊ตฌ์กฐ
      ์‚ผ์„ฑsw์—ญํ…Œ
      ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค
      ์‹œ๋ฎฌ๋ ˆ์ด์…˜
      ์ด์ง„ํƒ์ƒ‰
      Java
      JavaScript
      sort
      ์นด์นด์˜ค
      ์•Œ๊ณ ๋ฆฌ์ฆ˜
      ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
      programmers
      DART
      BAEKJOON
      ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ
    • ์ตœ๊ทผ ๋Œ“๊ธ€

    • ์ตœ๊ทผ ๊ธ€

    • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.1
    S.Honey
    43. ์Šค๋ ˆ๋“œ์™€ ํƒœ์Šคํฌ
    ์ƒ๋‹จ์œผ๋กœ

    ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”