2012-02-07 3 views
1

한 번에 두 개의 IRC 연결을 실행하는 C# 프로그램을 작성하고 있습니다. 연결은 나사, 그리고 각 스레드과 같이 시작합니다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() 메서드가 끝나면 스레드가 끝나고 프로그램 (콘솔 응용 프로그램)이 종료됩니다.

이전에 StartMainProcessor()에서 while (true) {}을 추가하여이 문제를 극복했습니다. 그러나이 작업은 100 % CPU를 소비하며 실제로 다른 점을 선호합니다. 해결책.

도움 주셔서 감사합니다. :)

+0

previosu 연결과 동일한 스레드에서 다시 연결해야합니까? –

답변

2

신호 구조가 필요한 것 같습니다. 예를 들어, AutoResetEvent과 같은 것을 사용하여 Reconnect를 호출하는 스레드를 차단할 수 있습니다. 즉, Reconnect를 호출하고 타이머를 시작한 다음 스레드를 차단할 수 있습니다. 그런 다음 타이머가 만료 된 이벤트 처리기에서 자동 재설정 이벤트를 설정하여 스레드가 계속 (차단 해제) 및 연결을 허용하도록합니다.

무한 루프 또는 sleeps in loops을 추가 할 때 나는 엄청난 양의 CPU 리소스를 낭비합니다.

1

Thread.Sleep 안에 Bot.Reconnect을 보내시겠습니까? 그러면 스레드를 계속 활성화하고 Bot.Connect에 다시 전화 할 준비가되었을 때 깨어납니다.

+0

+1 수면/연결/수신 루프가 분명한 해결책입니다. 아마도 sleep()이 anti-pattern이고 타이머가 대신 사용되어야한다고 말하는 모든 게시물 때문에 OP에서 사용하지 않았을 것입니다 : ( –

+0

그게 더 합리적이라고 생각합니다.) Thread.Sleep() 나쁜 것 같아요. 나는 인터넷을 덜 듣게 될 것 같아요. 하하. :) 고마워요, Daren. – Xenoprimate

+0

@MartinJames,'Thread.Sleep' ** is is ... 안티 패턴 ... 그것은 상대적으로 무해하지만 그것은 여전히 ​​반대입니다. - 패턴. – Kiril

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

0

어떻게 당신이 Main 방법을 가정, 그렇게하지 않는 이유는 우리가 거기서부터 시작이

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

같은 약 :

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에서 어떤 것을 듣는다 고 가정하고 그 작업을 더 이상 수행 할 필요가 없다고 결정할 때까지 데이터를 처리합니다.