繁体   English   中英

C#使线程等待计时器

[英]C# Making a Thread wait for a 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;
            }
        }

在bot断开连接之前,此方法可以正常工作(最终将始终发生,这是IRC的本质)。 断开连接时,将调用Reconnect(),这将启动计时器。 当该计时器到期时,该机器人应再次调用Connect()。 使用计时器的原因是IRC服务器有时会拒绝立即重新连接。

但是,一旦Connect()方法结束,则线程结束,并且程序(控制台应用程序)退出。 (Client.Listen()正在阻止)

我以前通过在StartMainProcessor()中添加while(true){}来克服了这个问题,但是这会消耗100%的CPU,因此我真的希望使用其他解决方案。

谢谢您的帮助。 :)

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

我不喜欢旋转处理器-在添加无限循环或循环睡眠时会浪费大量CPU资源。

您为什么不只在Bot.Reconnect内部Bot.Reconnect Thread.Sleep 这样可以使线程保持活动状态,并在准备再次调用Bot.Connect时将其唤醒。

您可能想尝试类似的方法

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/zh-CN/library/aa645740(v=vs.71).aspx

这样的事情怎么样

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);
            }
        }
    }
}

我假设您有一个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中侦听某些内容),然后处理数据,直到您决定不再需要进行此工作为止。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM