ํ๋ก์ธ์ค(Process)
: ์คํํ์ผ์ด ์คํ๋์ด ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฌ๋ ์ธ์คํด์ค- ํ๋ก์ธ์ค๋ ํ๋ ์ด์์
์ค๋ ๋(Thread)
๋ก ๊ตฌ์ฑ๋๋ค. - ์ค๋ ๋๋ ์ด์์ฒด์ ๊ฐ CPU๋ฅผ ํ ๋นํ๋ ๊ธฐ๋ณธ๋จ์์ด๋ฉฐ, ํ๋ก์ธ์ค๊ฐ ๋ฐง์ค์ด๋ผ๋ฉด, ์ค๋ ๋๋ ๋ฐง์ค์ ์ด๋ฃจ๊ณ ์๋ ์ค์ด๋ผ๊ณ ํ ์ ์๋ค.
๋ฉํฐ ์ค๋ ๋(Multi-Thread)๋ฅผ ์ด์ฉํ์๋์ ์ฅ๋จ์ .
์ฅ์
์ฌ์ฉ์ ๋ํํ ํ๋ก๊ทธ๋จ์์(์ฝ์ ํ๋ก๊ทธ๋จ๊ณผ GUIํ๋ก๊ทธ๋จ ๋ชจ๋) ๋ฉํฐ์ค๋ ๋๋ฅผ ์ด์ฉํ๋ฉด ์๋ต์ฑ์ ๋์ผ ์ ์๋ค๋ ์ ์ ๊ผฝ์ ์ ์๋ค.
- ์๋ฅผ ๋ค์ด ์ฐ๋ฆฌ๊ฐ ๋ง๋ ํ๋ก๊ทธ๋จ์ ํ์ผ์ ๋ณต์ฌํ๋๋ฐ, ๋ณต์ฌํ ํผ์ผ์ด ๋๋ฌด ์ปค์ ์์์๊ฐ์ด 30๋ถ์ ๋ ๊ฑธ๋ฆฐ๋ค๊ณ ๊ฐ์ ํด๋ณด์. ์ด ๋ ํ๋ก๊ทธ๋จ์ ๋จ์ผ ์ค๋ ๋๋ก ๋ง๋ ๋ค๋ฉด ํ๋ก๊ทธ๋จ์ด ํ์ผ์ ๋ณต์ฌํ๋ ๋์ ์ฌ์ฉ์๊ฐ ์ทจ์ ๋ช ๋ น์ ๋ด๋ฆฌ๊ณ ์ถ์ด๋ ํ๋ก๊ทธ๋จ์ด ์ฌ์ฉ์์๊ฒ ๋ฐ์ํ์ง ์์ผ๋ฏ๋ก, ๋ณต์ฌ๋ฅผ ์ทจ์ํ ์๊ฐ ์๋ค. ์์ ๊ด๋ฆฌ์๋ฅผ ์ด์ฉํด ๊ฐ์ ๋ก ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃ์ํค์ง ์๋ ํ.. ์ด ํ๋ก๊ทธ๋จ์ ์ฌ์ฉ์์์ ๋ํ๋ฅผ ์ํ ์ค๋ ๋๋ฅผ ํ๋ ๋ ์ถ๊ฐํ๋ค๋ฉด ํ์ผ๋ณต์ฌ๋ฅผ ํ๋ฉด์๋ ์ฌ์ฉ์๋ก๋ถํฐ ๋ช ๋ น์ ๋ฐ์ ์ ์๋ค.
๋ฉํฐ ํ๋ก์ธ์ค ๋ฐฉ์์ ๋นํด ๋ฉํฐ ์ค๋ ๋ ๋ฐฉ์์ด ์์๊ณต์ ๊ฐ ๋ ์ฝ๋ค๋ ์ ์ด ์๋ค.
- ๋ฉํฐ ํ๋ก์ธ์ค๋ GUI๊ฐ ์๋ ์น์๋ฒ๊ฐ์ ์๋ฒ์ฉ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ง์ด ์ทจํ๋ ๊ตฌ์กฐ์ธ๋ฐ, ํ๋ก์ธ์ค๋ผ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๊ตํํ๋ ค๋ฉด ์์ผ์ด๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ IPC(Inter Process Communication)๋ฅผ ์ด์ฉํด์ผ ํ๋ค. ๋ฐ๋ฉด ๋ฉํฐ ์ค๋ ๋ ๋ฐฉ์์์๋ ๊ทธ์ ์ค๋ ๋๋ผ๋ฆฌ ์ฝ๋ ๋ด์ ๋ณ์๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒ๋ง์ผ๋ก๋ ๋ฐ์ดํฐ ๊ตํ์ ํ ์ ์๋ค.
- ํ๋ก์ธ์ค๋ฅผ ๋์ฐ๊ธฐ ์ํด ๋ฉ๋ชจ๋ฆฌ์ ์์์ ํ ๋นํ๋ ์์ ์ (CPU ์ฌ์ฉ์๊ฐ๋ฑ์) ๋น์ฉ์ด ๋น์ผ๋ฐ, ์ค๋ ๋๋ฅผ ๋์ธ๋๋ ์ด๋ฏธ ํ๋ก์ธ์ค์ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ์ ์์์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ์ ์์์ ํ ๋นํ๋ ๋น์ฉ์ ์ง๋ถํ์ง ์์๋ ๋๋ค.
๋จ์
- ๊ตฌํํ๊ธฐ๊ฐ ๋งค์ฐ ๊น๋ค๋กญ๋ค.
- ํ ์คํธํ๊ธฐ๊ฐ ์ฝ์ง ์๋ค.
- ๋ฉํฐ ํ๋ก์ธ์ค ๊ธฐ๋ฐ์ ์ํํธ์จ์ด๋ ์ฌ๋ฌ ๊ฐ์ ์์ํ๋ก์ธ์ค ์ค ํ๋์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ์ํฅ์ด ํ์ฐ๋์ง ์์ง๋ง, ๋ฉํฐ ์ค๋ ๋ ๊ธฐ๋ฐ์ ์ํํธ์จ์ด์์๋ ์์ ์ค๋ ๋ ์ค ํ๋์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ์ ์ฒด์ ์ํฅ์ ๋ฏธ์น๋ค.
- ๋ฉํฐ์ค๋ ๋์์ ์ค๋ ๋๋ฅผ ๋๋ฌด ๋ง์ด ์ฌ์ฉํ๋ฉด ์คํ๋ ค ์ฑ๋ฅ์ด ์ ํ๋๋ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค.
- ์ค๋ ๋๊ฐ 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 ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ์ผ์ด๋๋ ์ผ
- ํํธ,
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
- ๊ต์ฌ์ ์ ์๋ ์ฝ๋์๋ ์ฐจ์ด๊ฐ ์๋ค. ๊ต์ฌ์์๋ ๋ง์ง๋ง์ 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 ์ฐ์ฐ์๊ฐ ์ด๋ป๊ฒ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ํ์ฑํ๋์ง์ ๋ํ ์ดํด๋์ ์ด๋ฏธ์ง]
- ์ ๊ทธ๋ฆผ์์
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.
๊ณผ์
[๊ตฌํ๋ด์ฉ]
์ ๋ ฅ 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 |