user866852
user866852

Reputation:

Threading.Timer stops in Console application

I'm working with with a dictionary containing a ID as key and a queue as the value. I have one thread writing to the queues, and another thread reading from the queues, so I need to use the Concurrent-structures that were introduced in .NET 4.0. As a part of this i tried to write a test application just to fill the queues, but I came across an issue with the timers stopping after around 10 seconds. I really don't understand why as there is nothing to catch, no error message or anything to give me a hint about what might be wrong.

So can someone please explain to me why the timer stops after around 10 seconds? I've tried this on two different computers (both using Visual Studio 2012, but with .NET Framework 4.0).

class Program {

    private readonly ConcurrentDictionary<int, ConcurrentQueue<TestObject>> _pipes = 
        new ConcurrentDictionary<int, ConcurrentQueue<TestObject>>();

    static void Main() {
        Program program = new Program();
        program.Run();
        Console.Read();
    }

    private void Run() {
        _pipes[100] = new ConcurrentQueue<TestObject>();
        _pipes[200] = new ConcurrentQueue<TestObject>();
        _pipes[300] = new ConcurrentQueue<TestObject>();

        Timer timer = new Timer(WriteStuff, null, 0, 100);
    }

    private void WriteStuff(object sender) {
        for (int i = 0; i < 5; i++) {
            foreach (KeyValuePair<int, ConcurrentQueue<TestObject>> pipe in _pipes) {
                pipe.Value.Enqueue(
                    new TestObject { Name = DateTime.Now.ToString("o") + "-" + i });
            }
            i++;
        }
        Console.WriteLine(DateTime.Now + "added stuff");
    }
}

internal class TestObject {
    public string Name { get; set; }
    public bool Sent { get; set; }
}

Upvotes: 2

Views: 1295

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 133995

Most likely, the timer is going out of scope and being collected. Declare the timer at outer scope. That is:

private Timer timer;
private void Run()
{
    ...
    timer = new Timer(WriteStuff, null, 0, 100);
}

Also, I think you'll find that BlockingCollection is easier to work with than ConcurrentQueue. BlockingCollection wraps a very nice API around concurrent collections, making it easier to do non-busy waits on the queue when removing things. In its default configuration, it uses a ConcurrentQueue as the backing store. All you have to do to use it is replace ConcurrentQueue in your code with BlockingCollection, and change from calling Enqueue to calling Add. As in:

for (int i = 0; i < 5; i++)
{
    foreach (var pipe in _pipes)
    {
        pipe.Value.Add(
            new TestObject { Name = DateTime.Now.ToString("o") + "-" + i });
    }
}

Upvotes: 4

Related Questions