2012-11-25 77 views
2

這樣簡單!這是我的一個嘗試,它要求函數通過自身的pausable部分使用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.在遊戲的主循環中被處理。

我想它會使它成爲某種僞線程?無論如何。

它將允許暴徒在每個循環中逐位處理此動作,而不是在A.I中進行級聯檢查。像...

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) 

現在,我實現了我無法弄清楚如何修復一個bug。當它應該取消暫停BlackThread時,它在使用它的函數(在本例中爲pausableFunction())中保持暫停狀態。我想這是因爲該實例是如何傳遞的?

如果這是我的猜測 - 也就是說,某些東西(我猜想它是布爾暫停)是通過值而不是引用傳遞的 - 我該如何解決它?我真的習慣了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

Spinwait,例如'while(!paused && IsAlive);'應該*真的被避免。您應該執行阻止等待。 – 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和另一個在主循環中管理的暫停ARE,並使用支持BlackThread的函數暫停該線程;也就是說,已經訪問了一個BlackThread實例。

在這種情況下,我使用了靜態BlackThread對象,但它也可以作爲參數傳遞給函數。

是的,它的名字是佛教地獄!