Search code examples
c#multithreadingautoreseteventwaitone

C# Signaling two threads with AutoResetEvent



I need to create a program that counts to 10 using two threads.
one threads should print even numbers and the other should print odd numbers.
These threads should print the numbers in order (1, 2, 3, 4, 5...)

I have done this code but it seems not to work... any ideas?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        private static AutoResetEvent autoEvent;
        private static int num = 10;

        static void DoWork(object data)
        {
            var counter = (int)data;

            if (counter == 1)
            {
                autoEvent.WaitOne();
            }

            while (counter <= num)
            {
                Console.WriteLine(counter);
                counter += 2;
                autoEvent.Set();
                autoEvent.WaitOne();
            }
        }

        static void Main(string[] args)
        {
            autoEvent = new AutoResetEvent(false);

            var evenCounter = new Thread(DoWork);
            evenCounter.Start(0);

            var notEvenCounter = new Thread(DoWork);
            notEvenCounter.Start(1);

            Console.ReadLine();
        }
    }
}

Solution

  • In that code autoEvent.WaitOne() may not block because the AutoResetEvent is already in signaled state:

            autoEvent.Set();
            autoEvent.WaitOne();
    

    So that thread will not wait for another thread as you planned.
    To solve that problem you need to use 2 AutoResetEvents. One thread will wait on the first AutoResetEvent, second thread will wait on the second AutoResetEvent. Each thread will signal an AutoResetEvent that 'belongs' to another thread.
    To demonstrate my idea I'll show you the lines of code only where you need to make a change:

    private static AutoResetEvent autoEvents[] = new AutoResetEvent[2];
    

    ...

    autoEvents[0] = new AutoResetEvent(false);
    autoEvents[1] = new AutoResetEvent(false);
    

    ...

    var counter = (int)data;
    int initial_counter = counter;
    

    ...

    if (counter == 1)
    {
    autoEvents[initial_counter].WaitOne();
    }
    

    ...

    autoEvents[1 - initial_counter].Set();
    autoEvents[initial_counter].WaitOne();
    

    At the end of DoWork signal the appropriate AutoResetEvent to avoid infinite blocking of another thread:

    autoEvents[1 - initial_counter].Set();