C# 문법 공부 : Threading - 2
pTask1
using System;
using System.Threading.Tasks;
namespace Threading;
class Task1 //Task 클래스
{
public void DoTest()
{
// Task.Factory를 이용하여 쓰레드 생성과 시작
// Task.Factory : Task 및 Task<TResult> 인스턴스를 만들고 구성하는 팩터리 메서드에 대한 액세스를 제공
Task.Factory.StartNew(new Action<object>(Run), null);
Task.Factory.StartNew(new Action<object>(Run), "1st");
Task.Factory.StartNew(Run, "2nd");
Console.Read();
}
static void Run(object data)
{
Console.WriteLine(data == null ? "NULL" : data);
}
}
pTask2
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Threading;
class pTask2 //Task 클래스
{
public void DoTest()
{
// Task<T>를 이용하여 쓰레드 생성과 시작
Task<int> task = Task.Factory.StartNew<int>(() => CalcSize("Hello World"));
Console.WriteLine("1.xx");
Thread.Sleep(1000); // 메인쓰레드에서 다른 작업 실행
Console.WriteLine("3.zz");
int result = task.Result; // 쓰레드 결과 리턴.
// 쓰레드가 계속 실행중이면 이곳에서 끝날 때까지 대기함
Console.WriteLine("4.Result={0}", result);
}
static int CalcSize(string data)
{
string s = data == null ? "" : data.ToString();
// 복잡한 계산 과정
Console.WriteLine("2.ss");
return s.Length;
}
}
pParallel1
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Threading;
class pParallel1 //Parallel 예제
{
/*
Parallel 병렬 루프 및 영역에 대한 지원을 제공
CPU가 가지고 있는 코어 및 스레드에 나누어서 병렬 처리가 이루어짐
결과는 뒤죽박죽으로 올라오지만 처리속도가 뛰어남
*/
static int N = 10;
public void DoTest()
{
// delegate
Console.Write("delegate : ") ;
Parallel.For(1, N, delegate(int i){ //Parallel.For(시작값, 종료값, delegate(int i){});
// Do Work.
Console.Write(i + " / ") ;
});
Console.WriteLine("");
// 람다식
Console.Write("람다식 : ") ;
Parallel.For(1, N, i => { //Parallel.For(시작값, 종료값, i => {});
// Do Work.
Console.Write(i + " / ") ;
});
Console.WriteLine("");
// 메소드(함수)
Console.Write("Method : ") ;
Parallel.For(1, N, Method2); //Parallel.For(시작값, 종료값, Method2);
Console.WriteLine("");
}
static void Method2(int i)
{
// Do work.
Console.Write(i + " / ") ;
}
}
pParallel2
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Threading;
class pParallel2 //Parallel 클래스 Thread 사용
{
public void DoTest()
{
/*
Thread.CurrentThread 현재 실행 중인 스레드를 가져옴
Thread.ManagedThreadId 현재 관리되는 스레드의 고유 식별자를 가져옴
Parallel 병렬 루프 및 영역에 대한 지원을 제공
Parallel.For(시작값, 종료값, i => {});
*/
// 1. 순차적 실행 : 동일쓰레드가 0~999 출력
for (int i = 0; i < 1000; i++)
{
Console.Write("{0}: {1} / ", Thread.CurrentThread.ManagedThreadId, i);
if(i%10==0) Console.WriteLine("");
}
Console.Read();
Console.WriteLine("===========================================================");
Console.WriteLine("===========================================================");
// 2. 병렬 처리 : 다중쓰레드가 병렬로 출력
Parallel.For(0, 1000, (i) => {
Console.Write("{0}: {1} / ", Thread.CurrentThread.ManagedThreadId, i);
if(i%10==0) Console.WriteLine("");
});
}
}
pMultiThrdApp
using System;
using System.IO;
using System.Net;
using System.Timers;
using Timer = System.Timers.Timer;
namespace Threading;
class pMultiThrdApp //웹페이지 읽어서 1분마다 파일 생성
{
public void DoTest()
{
// 타이머 생성 및 시작
Timer timer = new System.Timers.Timer();
timer.Interval = 60 * 1000; // 1분 : 60*1초
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
// 쓰레드풀의 작업쓰레드가 지정된 시간 간격으로
// 아래 이벤트 핸들러 실행
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// 웹페이지 html문을 다운로드
WebClient web = new WebClient();
string webpage = web.DownloadString("https://www.naver.com/");
// 다운로드 내용을 파일에 저장
string time = DateTime.Now.ToString("yyyyMMdd_hhmmss");
string outputFile = string.Format("page_{0}.html", time);
Console.WriteLine(outputFile);
File.WriteAllText(outputFile, webpage);
}
}
pCountdownEvent
using System;
using System.Threading;
namespace Threading;
class pCountdownEvent
{
/*
CountdownEvent - 한 쓰레드에서 복수 쓰레드들로부터의 신호들을 기다리는데 사용된다.
ManualResetEvent가 한 쓰레드에서 신호(Signal)을 보내 복수 쓰레드들을 통제하는데 사용되는것
아래는 10개의 쓰레드를 시작한 후, 이 쓰레드들로부터 처음 5개의 신호가 (CountdownEvent.Signal() 메서드)
먼저 도착하는 대로 메인쓰레드는 Wait 대기 상태를 해제하고 다음 문장을 실행하게 된다.
CountdownEvent.CurrentCount 이벤트를 설정하는 데 필요한 남아 있는 신호의 수를 가져옵니다.
CountdownEvent.Signal() CountdownEvent의 값을 줄이면서 신호를 CurrentCount에 등록합니다.
countEvent.Wait() CountdownEvent가 설정될 때까지 현재 스레드를 차단합니다.
*/
static CountdownEvent countEvent = new CountdownEvent(5); // CountdownEvent 객체 필드
public void DoTest()
{
// 10개의 쓰레드 시작
// 10개중 5개만 Vote만 끝내면 중지
for (int i = 0; i < 10; i++)
{
new Thread(Vote).Start(i);
}
// 메인쓰레드 첫 5개 신호를 기다림, 5개가 들어오면 신호 풀림. 숫자 설정은 이벤트 객체에서 설정
countEvent.Wait();
Console.WriteLine("Vote is done!");
}
static void Vote(object id)
{
if(countEvent.CurrentCount > 0){
countEvent.Signal(); // CountdownEvent 신호. -1씩 카운트다운.
Console.WriteLine("{0}: Vote", id);
}else{
Console.WriteLine("{0}: No vote", id);
}
}
}
pLock
using System;
using System.Threading;
namespace Threading;
class pThreadLock //Thread Unsafe,safe
{
/*
lock(abc){} 단일 스레드가 해당 개체에 대한 단독 액세스 권한을 가짐
*/
private int counter = 1000;
private object lockObject = new object(); // lock문에 사용될 객체
public void DoTest()
{
for (int i = 0; i < 10; i++) // 10개의 쓰레드가 동일 메서드 실행
{
//new Thread(UnsafeCalc).Start(); //1010 / 1010 / 1010 / 1010 / 1010 / 1010 / 1010 / 1010 / 1010 / 1010 /
new Thread(SafeCalc).Start(); //1001 / 1002 / 1003 / 1004 / 1005 / 1006 / 1007 / 1008 / 1009 / 1010 /
}
}
// Thread-Safe하지 않은 메서드
private void UnsafeCalc()
{
counter++; // 객체 필드를 모든 쓰레드가 자유롭게 변경
// 가정 : 다른 복잡한 일을 한다
for (int i = 0; i < counter; i++)
for (int j = 0; j < counter; j++) ;
Console.Write(counter + " / "); // 필드값 읽기
}
// Thread-Safe 메서드
private void SafeCalc()
{
lock (lockObject) // 한번에 한 쓰레드만 lock블럭 실행
{
counter++; // 필드값 변경
// 가정 : 다른 복잡한 일을 한다
for (int i = 0; i < counter; i++)
for (int j = 0; j < counter; j++) ;
Console.Write(counter + " / "); // 필드값 읽기
}
}
}
'C#' 카테고리의 다른 글
C# 문법 공부 : Threading - 3 (0) | 2024.05.03 |
---|---|
C# 문법 공부 : Threading - 1 (0) | 2024.05.03 |
C# 문법 공부 : ThreadingForm (0) | 2024.04.29 |
C# 문법 공부 : WindowsForms (0) | 2024.04.29 |
C# 문법 공부 : Timer (0) | 2024.04.29 |