2012-02-07 106 views
1

我在寫一個C#程序,它一次運行兩個IRC連接。 的連接線程,每個線程開始像這樣:C#使線程等待定時器

MainThread = new Thread(new ThreadStart(StartMainProcessor)); 
      MainThread.IsBackground = false; 
      MainThread.Start(); 

private void StartMainProcessor() { 
      MainProcessor.Bot.Connect(); 
      //while (true) { } 
     } 

Bot.Connect()看起來像這樣(有點刪節版):

public void Connect() { 
      try { 
       Client.Connect(IRCHelper.SERVER, IRCHelper.PORT); 
      } 
      catch (CouldNotConnectException e) { 
       Reconnect(true); 
       return; 
      } 

      try { 
       Client.Listen(); 
      } 
      catch (Exception e) { 
       Reconnect(false); 
       return; 
      } 
     } 

這工作得很好,直到機器人斷開連接(這總是會最終發生,這是IRC的本質)。 當它斷開連接時,將調用Reconnect(),啓動一個計時器。當該計時器到期時,殭屍意味着再次調用Connect()。計時器的原因是IRC服務器有時會拒絕立即重新連接。

但是,一旦Connect()方法結束,線程結束,程序(控制檯應用程序)退出。 (Client.Listen()被阻塞)

我以前通過在StartMainProcessor()中添加while(true){}來克服了這個問題...但是這樣吃了100%的CPU,我真的更喜歡不同的解。

謝謝你的幫助。 :)

+0

是否必須重新連接是由與previosu連接相同的線程進行的? – 2012-02-07 10:52:43

回答

2

聽起來像你需要一個信號結構。例如,您可以使用類似AutoResetEvent的東西來阻止線程調用重新連接,即調用重新連接,啓動計時器,然後阻止線程。然後在timer expired事件處理程序中設置自動重置事件,以允許線程繼續(取消阻止)並調用Connect。

我不喜歡旋轉處理器 - 當您添加無限循環或sleeps in loops浪費大量的CPU資源。

1

爲什麼你不只是Thread.Sleep裏面Bot.Reconnect?這會使線程保持活動狀態,並在準備再次撥打Bot.Connect時將其喚醒。

+0

+1睡眠/連接/偵聽迴路是顯而易見的解決方案。可能不被OP使用,因爲所有的帖子都說sleep()是反模式,必須使用定時器:(( – 2012-02-07 10:28:54

+0

我想這樣做更有意義,我確實有Thread.Sleep()是的,我猜我應該聽聽互聯網,哈哈:)謝謝,達人 – Xenoprimate 2012-02-07 10:36:28

+0

@MartinJames,'Thread.Sleep' ** IS **反模式...它是相對無害的,但它仍然是一個反-pattern。 – Kiril 2012-02-07 16:01:13

0

你可能想嘗試類似的東西

private bool canExitThread; 
private void StartMainProcessor() 
{ 
    while (canExitThread) 
    { 
     //do the magic here 
     System.Threading.Thread.Sleep(1); //make sure you allow thread to do the job, otherwise you will get 100 cpu usage 

     //do the connecting, disconnecting, listening 
    } 
} 

你也可以檢查,如果客戶端連接?如果是這樣,那麼你應該檢查在主循環內,如果它斷開連接 - 調用connect方法。

希望能給你一個想法如何去做。

也看看下面的文章,這可能會解釋一些更多的東西。 http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx

+0

Icky!不要這樣做......他可以阻止輸入,信號燈或手動重置事件,告訴他什麼時候退出。 – Kiril 2012-02-07 16:04:06

0

如何對這樣的事情

using System; 
using System.Diagnostics; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Server 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Starting server.."); 

      foreach (var connection in new[] {new Connection(TimeSpan.FromSeconds(1)), new Connection(TimeSpan.FromSeconds(1))}) 
       ThreadPool.QueueUserWorkItem(connection.Connect); 

      Console.WriteLine("Server running. Press Enter to quit."); 

      Console.ReadLine(); 
     } 
    } 

    public class Connection //might be good to implement IDisposable and disconnect on Dipose() 
    { 
     private readonly TimeSpan _reConnectionPause; 

     public Connection(TimeSpan reConnectionPause) 
     { 
      _reConnectionPause = reConnectionPause; 
     } 

     //You probably need a Disconnect too 
     public void Connect(object state) 
     { 
      try 
      { 
       //for testing assume connection success Client.Connect(IRCHelper.SERVER, IRCHelper.PORT); 
       Debug.WriteLine("Open Connection"); 
      } 
      catch (Exception) 
      { 
       //You might want a retry limit here 
       Connect(state); 
      } 

      try 
      { 
       //Client.Listen(); 
       //Simulate sesison lifetime 
       Thread.Sleep(1000); 
       throw new Exception(); 
      } 
      catch (Exception) 
      { 
       Debug.WriteLine("Session end"); 
       Thread.Sleep(_reConnectionPause); 
       Connect(state); 
      } 
     } 
    } 
} 
0

我相信你有Main方法,所以我們爲什麼不從那裏開始:

private static readonly MAX_NUM_BOTS = 2; 

static void Main(string[] args) 
{ 
    List<Thread> ircBotThreads = new List<Thread>(); 
    for(int numBots = 0; numBots < MAX_NUM_BOTS; numButs++) 
    { 
     Thread t = new Thread(()=>{StartMainProcessor();}); 
     t.IsBackground = false; 
     t.Start(); 
     ircBotThreads.Add(t); 
    } 

    // Block until all of your threads are done 
    foreach(Thread t in ircBotThreads) 
    { 
     t.Join(); 
    } 

    Console.WriteLine("Goodbye!"); 
} 

private static void StartMainProcessor() 
{ 
    MainProcessor.Bot.Connect(); 
} 

然後,你可以這樣做:

// 30 second time out (or whatever you want) 
private static readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(30.0); 

// specify the maximum number of connection attempts 
private static readonly int MAX_RECONNECTS = 10; 

public void Connect() 
{ 
    bool shouldListen = false; 
    // This is your connect and re-connect loop 
    for(int i = 0; i < MAX_RECONNECTS; i++) 
    { 
     try 
     { 
      Client.Connect(IRCHelper.SERVER, IRCHelper.PORT); 
      shouldListen = true; 
     } 
     catch (CouldNotConnectException e) 
     { 
      // It's OK to sleep here, because you know exactly 
      // how long you need to wait before you try and 
      // reconnect 
      Thread.Sleep((long)TIMEOUT.TotalMilliseconds); 
      shouldListen = false; 
     } 
    } 

    while(shouldListen) 
    { 
     try 
     { 
      Client.Listen(); 
     } 
     catch (Exception e) 
     { 
      // Handle the exception 
     } 
    } 
} 

這是一個非常粗糙的d筏,但其概念是,你一直試圖重新連接,直到你失敗。一旦你連接了,你就可以聽(我假定你在IRC中聽一些東西),並處理這些數據,直到你決定不再需要做這項工作。