2012-11-25 3 views
2

Simple this this! 이것은 하나의 시도입니다.이 함수를 사용하려면 스레드에서 처리 할 함수에 일시 중지 가능한 섹션에서 Pause() 함수를 사용해야합니다.일시 중지 가능한 스레드 클래스 구현

using System; 
using System.Threading; 

class BlackThread { 
    private bool paused; 
    private Thread innerThr; 

    // --- 

    public bool IsAlive { 
     get { 
      return innerThr.IsAlive; 
     } 
    } 

    // === 

    public void SetAndGo (ThreadStart start) { 
     paused = false; 

     innerThr = new Thread(start); 
     innerThr.Start(); 
     WaitForIt(); 
    } 

    // --- 

    public void Pause() { 
     paused = true; 
     while (paused); 
    } 

    public void Unpause() { 
     paused = false; 
    } 

    public void WaitForIt() { 
     while(!paused && IsAlive); 
    } 

    public void Continue() { 
     Unpause(); 
     WaitForIt(); 
    } 
} 

class MainClass { 
    static void pausableFunction (BlackThread self) { 
     Console.WriteLine("* Waiting..."); 
     self.Pause(); 
     Console.WriteLine("* Doing stuff."); 
     self.Pause(); 
     Console.WriteLine("* Finished!"); 
    } 

    static void Main() { 
     BlackThread noir = new BlackThread(); 
     noir.SetAndGo(() => pausableFunction(noir)); 

     while (noir.IsAlive) { 
      Console.Write("> "); 
      Console.ReadKey(); 
      noir.Continue(); 
     } 
    } 
} 

슬프게도, 그것은 언제든지 일시 정지 할 수있는 하나는 아니지만, 외부 처리를 위해 기다릴 필요 기능에 대한 스레드를 계속할 수 있도록. 계속하기 전에 드로우 루프로 프레임을 그려야하는 게임 몹의 액션처럼, 몹의 A.I.는 게임의 메인 루프에서 처리됩니다.

나는 그것이 가짜 스레드의 일종으로 만들 것 같아요? 어쨌든.

mob는 A. 루프에서 계단식 검사 대신 비트마다이 작업을 비트 단위로 처리 할 수 ​​있습니다. 같은 ...

if mob is doing action { 
    if mob has already done this previous part of the action { 
     do the following part 
    } 
} 

... 그것은 오히려 스레드에서, 이렇게 될 줄 :

do the first step of the action 
Wait for it to be rendered... 
do the following step of the action 
Wait for it to be rendered... 
do the last step of the action 
(Action ends here, no need to wait for anything anymore) 

지금, 내 구현은 내가 해결하는 방법을 알아낼 수 없습니다 버그가 있습니다. BlackThread를 일시 중지 해제 할 예정이라면, BlackThread를 사용하는 함수 (이 경우 pausableFunction())에서 일시 중지 된 채로 있습니다. 나는 그것이 인스턴스가 전달 된 방법 때문이라고 생각하니?

내가 추측하고있는 것이면 - 즉, 무언가 (bool이 일시 중지 된 것 같습니다)는 참조 대신 값으로 전달됩니다. 어떻게 해결할 수 있습니까?

저는 C와 C++의 포인터에 익숙해 져 있습니다. 그래서 때때로 C#에서 스코프간에 오브젝트 값의 통신을 처리 할 때 다소 엉키게됩니다. 차라리 특정 클래스를 담당하는 모든이 것 때문에 나는 단지 그것을 사용하지 않는

using System; 
using System.Threading; 

class Program { 
    static bool paused; 

    static void Pause() { 
     paused = true; 
     while (paused); 
    } 

    static void Unpause() { 
     paused = false; 
    } 

    static void WaitForIt(Thread waited) { 
     while(!paused && waited.IsAlive); 
    } 

    static void Continue (Thread ToStop) { 
     Unpause(); 
     WaitForIt(ToStop); 
    } 

    static void SetAndGo (out Thread thread, ThreadStart Start) { 
     thread = new Thread(Start); 
     thread.Start(); 
     WaitForIt(thread); 
    } 

    // --- 

    static void thr (string chant) { 
     // Console.WriteLine("Waiting..."); 
     // Pause(); 
     // Console.WriteLine("{0}", chant); 
     // Pause(); 
     // Console.WriteLine("Well, I'm finished!"); 

     Console.WriteLine("I'm finished!"); 
    } 

    static void Main() { 
     // Thread tt = new Thread(() => thr()); 
     // tt.Start(); 
     // WaitForIt(tt); 

     Thread tt; 
     SetAndGo(out tt, (() => thr("I'm doing stuff."))); 

     while (tt.IsAlive) { 
      Console.Write("> "); 
      Console.ReadKey(); 
      Continue(tt); 
     } 
    } 
} 

:


이 여기에이 작품, 프로토 타입이 말을하는 코드의 버전입니다 이 문제에 대해서는 가독성을 높이기위한 것입니다.

+2

'while (! paused && IsAlive);'과 같은 Spinwait은 실제로는 피해야합니다. 대신 차단 대기를 수행해야합니다. – Servy

+0

@Servy 매우 좋습니다. 그렇다면 정확히 무엇을 추천 하시겠습니까? 나는 Monitor Pulse와 Wait을 사용하려고 생각했지만, 제대로 이해할 수는 없다. – Mutoh

+1

'ManualResetEvent' 나'Semaphore'를 포함하여 꽤 많은 옵션이 있습니다. – Servy

답변

1

좋아, 나는 이미 시도한 것을 수행 했으므로 나중에 참조 할 수 있도록 여기에 코드를 남겨 두겠습니다.

이 결국 BlackThread 클래스입니다 : 여기

using System; 
using System.Threading; 

class BlackThread { 
    //* ===== *// 

    private AutoResetEvent pauser = new AutoResetEvent(false); 
    private AutoResetEvent waiter = new AutoResetEvent(false); 

    private Thread innerThr; 

    // ----- // 

    public bool IsActing { 
     get { 
      if (innerThr != null) return innerThr.IsAlive; 
      else return false; 
     } 
    } 

    //* ===== *// 

    public void KickStart_(ThreadStart start) { 
     innerThr = new Thread(start); 
     innerThr.Start(); 

     WaitForIt(); 
    } 

    // ----- // 

    // FOR THE THREADED FUNCTION 
    public void Wait() { 
     waiter.Set(); 
     pauser.WaitOne(); 
    } 

    public void End() { 
     waiter.Set(); 
    } 

    // ----- // 

    // FOR BLACKTHREAD MANAGING 
    private void WaitForIt() { 
     waiter.WaitOne(); 
    } 

    public void Continue() { 
     if (IsActing) { 
      pauser.Set(); 
      WaitForIt(); 
     } 
    } 

    //* ===== *// 
} 

그리고, 그 사용의 예 : 나는 결국 사용하기로 선택했습니다 무엇

class MainClass { 
    static void pausableFunction() { 
     Console.WriteLine("* Waiting..."); 

     Event.Wait(); 

     Console.WriteLine("* Doing stuff."); 
     Thread.Sleep(1000); 

     Event.Wait(); 

     Console.WriteLine("* Finished!"); 

     Event.End(); 
    } 

    static void anotherFunction(int foo) { 
     Console.WriteLine("* Wanna know the value of a number?"); 

     Event.Wait(); 

     Console.WriteLine("* I'll tell you. It's {0}!", foo); 

     Event.End(); 
    } 

    static void simpleFunction() { 
     Console.WriteLine("* I'm done already!"); 
    } 

    static BlackThread Event = new BlackThread(); 
    static Random Rand = new Random(); 

    static void Main() {   
     int r; 

     do { 
      if (!Event.IsActing) { 
       Console.WriteLine(); 
       r = Rand.Next(3); 

       if (r == 0) { 
        Event.KickStart_(() => pausableFunction()); 
       } 
       else if (r == 1) { 
        simpleFunction(); 
       } 
       else { 
        Event.KickStart_(() => anotherFunction(Rand.Next(20) + 1)); 
       } 
      } 
      else { 
       Event.Continue(); 
      } 

      Console.Write("> "); 
      Console.ReadKey(); 
     } while(true); 
    } 
} 

두 개의 AutoResetEvent 핸들러가 있었다 . 하나는 일시 중지가 필요한 스레드의 기능으로 관리되며 주 루프, 웨이터 ARE 및 다른 메인 루프에서 관리되는 Pauser ARE를 일시 중지하고 BlackThread를 지원하는 기능을 가진 스레드를 일시 중지합니다. 즉, BlackThread 인스턴스에 대한 액세스가 있습니다.

이 경우 정적 BlackThread 객체를 사용했지만 매개 변수로 함수에 전달할 수도 있습니다.

그리고 예, 그것은 불교의 지옥 이름을 따서 명명되었습니다!

관련 문제