C#让线程等待定时器

时间:2012-02-07 10:16:01

标签: c# .net multithreading timer

我正在编写一个同时运行两个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,我真的更喜欢不同的解决方案。

感谢您的帮助。 :)

5 个答案:

答案 0 :(得分:2)

听起来你需要一个信号构造。例如,您可以使用类似AutoResetEvent的内容来阻止调用Reconnect的线程,即调用Reconnect,启动计时器然后阻止线程。然后在计时器过期事件处理程序中设置自动重置事件,以允许线程继续(解除阻塞)并调用Connect。

我不喜欢旋转处理器 - 当你添加无限循环或sleeps in loops时浪费了大量的CPU资源。

答案 1 :(得分:1)

为什么不在Thread.SleepBot.Reconnect?这将使你的线程保持活跃状态​​,并在准备再次呼叫Bot.Connect时将其唤醒。

答案 2 :(得分: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

答案 3 :(得分: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);
            }
        }
    }
}

答案 4 :(得分: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
        }
    }
}

这是一个非常粗略的草案,但概念是你一直试图重新连接,直到你失败。一旦你连接,然后你听(我认为你在IRC中听一些东西)并处理数据,直到你决定你不再需要做这项工作。