0

I have a working version of my program, where the main part of my program runs on the same thread as the GUI using a forms.timer.

I am trying to upgrade to a better version that uses 2 threads. One of my threads (that processes all of the information) needs to be called repeatedly (on a timer).

I am using the following from my main class:

Timer tmr = new Timer(new TimerCallback(bot.refresh), null, 0, 1000);

Where bot.refresh is the method I want to call every second (1000ms) until I stop it.

public void refresh(Object obj)
{
        Debug.WriteLine("Updated: " + DateTime.Now.ToString());
}

About 1/3rd of the time the timer will run stop and I will get this output:

Updated: 23/11/2013 4:37:24 PM
Updated: 23/11/2013 4:37:25 PM
Updated: 23/11/2013 4:37:26 PM
Updated: 23/11/2013 4:37:27 PM
Updated: 23/11/2013 4:37:28 PM
Updated: 23/11/2013 4:37:29 PM
Updated: 23/11/2013 4:37:30 PM
The thread '<No Name>' (0x3f20) has exited with code 0 (0x0).
The thread '<No Name>' (0x37a0) has exited with code 0 (0x0).

Any suggestions for why this could be happening?

Also, is there a better way I can do this? I have the feeling that this is an odd way to do it.

Thanks for your help.

EDIT:

Will this go out of scope? This way I can start the timer when I need to rather than when Main is constructed. For it to be referenced does it need to be in the constructor?

class Main
{
    Timer tmr;
    public Main()
    {

    }

    public void start()
    {
         tmr = new Timer (new TimerCallback(bot.refresh), null, 0, 1000);
    }
}

Thanks.

4

1 回答 1

3

Your timer goes out of scope and is eventually garbage collected and stops running. You must keep a reference to it so it does not go out of scope.

class MainClass
{
    public MainClass()
    {
        tmr = new Timer(new TimerCallback(bot.refresh), null, 0, 1000);
    }

    Timer tmr;
}

As for a better way to handle this, it depends on what bot.refresh is doing. However if possible I would use the Consumer-Producer model and have a collection of "queued work" that the 2nd thread just processes as it comes in (this might not work at all for you, like I said it depends on how bot.refesh works.)

class MainClass
{
    public MainClass()
    {
        bot = new Bot();
        botDataProducer = BotDataProducer();
        dataQueue = new BlockingCollection<BotData>();
        consumer = Task.Factory.Run(() => ProcessData, TaskCreationOptions.LongRunning);
        producer = Task.Factory.Run(() => GenerateData, TaskCreationOptions.LongRunning);

    }

    BlockingCollection<BotData> dataQueue;
    Task consumer;
    Task producer;
    Bot bot;
    BotDataProducer botDataProducer;

    private void ProcessData()
    {
        //blocks the thread when there is no data, automatically wakes up when data is added.
        foreach(var data in dataQueue.GetConsumingEnumerable())
        {
            bot.Refresh(data);
        }
    }

    private void GenerateData()
    {
        //Assume Next() returns "false" when there will be no more data to process
        // and blocks when there is no data currently but more could come.
        while(botDataProducer.Next())
        {
            dataQueue.Add(botDataProducer.Data);
        }

        //This allows the foreach loop in the other thread to exit when the queue is empty.
        dataQueue.CompleteAdding();
    }
}
于 2013-11-23T06:11:05.917 回答