C#다중 스레드(8): 스레드 완료

4739 단어
카탈로그
  • 문제 해결
  • Countdown Event 클래스
  • 구조 함수와 방법
  • 예제

  • 문제 하나를 해결하다
    만약 프로그램이 웹에 5번의 요청을 보내야 한다면, 네트워크 파동의 영향을 받아 어느 정도 요청이 실패할 확률이 있다.실패하면 다시 시도해야 한다.
    예제 코드는 다음과 같습니다.
        class Program
        {
            private static int count = 0;
            static void Main(string[] args)
            {
                for (int i = 0; i < 5; i++)
                    new Thread(HttpRequest).Start();            //     
    
                //               
                while (count < 5)
                {
                    Thread.Sleep(100);
                }
                Console.WriteLine("      ");
            }
    
    
            //       
            public static void HttpRequest()
            {
                Console.WriteLine("      ");
                //        ,     ,       
                bool isSuccess = (new Random().Next(0, 10)) % 2 == 0;
    
                // ... ...     HTTP
                Thread.Sleep(TimeSpan.FromSeconds(2));
    
                //        
                if (!isSuccess)
                {
                    Console.WriteLine($"    ,count={count}");
                    new Thread(() =>
                    {
                        HttpRequest();
                    }).Start();
                    return;
                }
                //       ,+1
                Interlocked.Add(ref count,1);
                Console.WriteLine($"    ,count={count}");
            }
        }
    

    코드가 너무 엉망이지만, 우리는 Countdown 이벤트 클래스를 사용하여 그것을 개조할 수 있다.
    Countdown Event 클래스
    계수가 0이 될 때 신호가 있는 상태에 있는 동기 기원을 나타낸다.
    즉 계수기를 설정하면 각 라인이 완성되면 1이 줄어들고 계수기가 0이 되면 모든 라인이 임무를 완성했다는 뜻이다.
    구조 함수와 방법
    Countdown Event 클래스의 구조 함수는 다음과 같습니다.
    구조 함수
    설명
    CountdownEvent(Int32)
    Countdown Event 클래스의 새 인스턴스를 초기화하려면 지정된 카운트를 사용합니다.
    Countdown Event 클래스의 일반적인 방법은 다음과 같습니다.
    메서드
    설명
    AddCount()
    Countdown Event 의 현재 수를 1 더하기.
    AddCount(Int32)
    Countdown Event의 현재 카운트를 지정된 값만큼 증가시킵니다.
    Reset()
    CurrentCount를 InitialCount 값으로 재설정합니다.
    Reset(Int32)
    InitialCount 속성을 지정된 값으로 재설정합니다.
    Signal()
    Countdown Event에 신호를 등록하고 CurrentCount의 값을 줄입니다.
    Signal(Int32)
    Countdown Event에 여러 개의 신호를 등록하면 CurrentCount의 값을 지정한 수량으로 줄일 수 있습니다.
    TryAddCount()
    CurrentCount에 대한 시도를 추가합니다.
    TryAddCount(Int32)
    지정된 값을 추가하려는 CurrentCount 시도
    Wait()
    Countdown Event가 설정될 때까지 현재 스레드를 차단합니다.
    Wait(CancellationToken)
    Countdown Event가 설정될 때까지 현재 스레드를 차단하면서 CancellationToken을 관찰합니다.
    Wait(Int32)
    Countdown Event가 설정될 때까지 현재 스레드를 차단하고 32비트 기호 정수를 사용하여 시간 초과를 측정합니다.
    Wait(Int32, CancellationToken)
    Countdown Event가 설정될 때까지 현재 스레드를 차단하고 32비트 기호 정수로 시간 초과를 측정하며 CancellationToken을 관찰합니다.
    Wait(TimeSpan)
    Countdown Event가 설정될 때까지 현재 스레드를 차단하고 Timespan을 사용하여 시간 초과를 측정합니다.
    Wait(TimeSpan, CancellationToken)
    Countdown Event가 설정될 때까지 현재 스레드를 차단하고 TimeSpan 측정 시간 초과를 사용하며 CancellationToken을 관찰합니다.
    API가 비교적 많으니, 괜찮아, 우리가 천천히 그것을 이해하자.
    예제
    우리는 장면 코드를 하나 작성하는데, 하나는 다섯 가지가 있는데, 완성해야 한다. 각각 다섯 명을 파견하여 실현해야 한다..Wait(); 한 라인에 사용하면 이 라인은 다른 라인이 임무를 완성한 후에야 계속 실행할 수 있습니다.Signal();는 작업 라인에서 Countdown 이벤트 대상에게 신호를 보내서 라인이 임무를 완성했음을 알리고 CountdownEvent.CurrentCount에서 1을 뺀다.
    계수기가 0일 때, 막힌 라인이 실행을 회복합니다.
    코드의 예는 다음과 같습니다.
        class Program
        {
            //      5   
            private static CountdownEvent countd = new CountdownEvent(5);
            static void Main(string[] args)
            {
                Console.WriteLine("      ");
                //     5   ,   5   
                for (int i = 0; i < 5; i++)
                {
                    Thread thread = new Thread(DoOne);
                    thread.Name = $"{i}";
                    thread.Start();
                }
    
    
                //         
                countd.Wait();
    
                Console.WriteLine("    ,    ");
                Console.ReadKey();
            }
    
            public static void DoOne()
            {
                int n = new Random().Next(0, 10);
                //     n      
                Thread.Sleep(TimeSpan.FromSeconds(n));
                //    ,     
                countd.Signal();
                Console.WriteLine($"    {Thread.CurrentThread.Name}      ");
            }
        }
    

    예는 매우 간단하다. 각 라인이 자신의 임무를 완성할 때 Signal() 방법을 호출하여 계수기를 1로 줄여야 한다..Wait(); 모든 퀘스트가 완성되기를 기다릴 수 있습니다.
    주의해야 할 것은 호출되지 않거나Signal() 계수기가 계속 0이 되지 않으면 Wait()는 무한히 기다릴 것이다.
    물론Wait() 대기시간을 설정할 수 있고,
    또 상용 방법 중에는 AddCount(),Reset() 등이 있다.
    이런 종류의 대기 제어 방식은 비교적 느슨하다. Wait() 이후에 도대체 언제 실행할 수 있는지는 모두 다른 라인의 자각에 달려 있다.
    만약 루틴이 작업 수행에 실패한 것을 발견하면, 우리는 Signal()를 호출하지 않거나 AddCount()를 사용하여 횟수를 늘리고 다시 시도할 수 있습니다

    좋은 웹페이지 즐겨찾기