C# 문법 공부 : Threading - 2

 

 

 

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