Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Threading, communication between two threads c#

I'm wondering what is the best way to implement communication between two threads. I have one thread that generates random number(class Sender) and now I want to have another thread(class Receiver) that 'll receive generated random number. This is Sender:

public  class Sender
{
    public int GenerateNumber(){


        //some code
        return randomNumber;
    }
}

Afcourse in Main function I'll start those threads:

static void Main(string[] args){

     Sender _sender=new Sender();
     Thread thread1=new Thread(new ThreadStart(_sender.GenerateNumber));

}

I appreciate your help

like image 670
Avicena00 Avatar asked Jan 06 '12 20:01

Avicena00


2 Answers

Here's a possible approach using a WaitHandle:

class Program
{
    static void Main(string[] args)
    {
        Sender _sender = new Sender();
        Receiver _receiver = new Receiver();

        using (ManualResetEvent waitHandle = new ManualResetEvent(false))
        {
            // have to initialize this variable, otherwise the compiler complains when it is used later
            int randomNumber = 0;

            Thread thread1 = new Thread(new ThreadStart(() =>
            {
                randomNumber = _sender.GenerateNumber();

                try
                {
                    // now that we have the random number, signal the wait handle
                    waitHandle.Set();
                }
                catch (ObjectDisposedException)
                {
                    // this exception will be thrown if the timeout elapses on the call to waitHandle.WaitOne
                }
            }));

            // begin receiving the random number
            thread1.Start();

            // wait for the random number
            if (waitHandle.WaitOne(/*optionally pass in a timeout value*/))
            {
                _receiver.TakeRandomNumber(randomNumber);
            }
            else
            {
                // signal was never received
                // Note, this code will only execute if a timeout value is specified
                System.Console.WriteLine("Timeout");
            }
        }
    }
}

public class Sender
{
    public int GenerateNumber()
    {
        Thread.Sleep(2000);

        // http://xkcd.com/221/
        int randomNumber = 4; // chosen by fair dice role

        return randomNumber;
    }
}

public class Receiver
{
    public void TakeRandomNumber(int randomNumber)
    {
        // do something
        System.Console.WriteLine("Received random number: {0}", randomNumber);
    }
}


I just wanted to update my answer to provide what I think is the equivalent code for the above example using the Task<TResult> class in .NET 4 pointed out by Jon Skeet in his answer. Credit goes to him for pointing it out. Thanks a lot, Jon. I haven't had a reason to use that class yet, and was pleasantly surprised when I saw how easy it was to use.

Aside from performance benefits that you gain under the hood from using this class, writing equivalent code using the Task<TResult> class seems to be much easier. For instance, body of the Main method above could be rewritten as shown below:

        Sender _sender = new Sender();
        Receiver _receiver = new Receiver();

        Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber);

        // begin receiving the random number
        getRandomNumber.Start();

        // ... perform other tasks

        // wait for up to 5 seconds for the getRandomNumber task to complete
        if (getRandomNumber.Wait(5000))
        {
            _receiver.TakeRandomNumber(getRandomNumber.Result);
        }
        else
        {
            // the getRandomNumber task did not complete within the specified timeout
            System.Console.WriteLine("Timeout");
        }

If you have no need to specify a timeout for the task and are content to wait indefinitely for it to finish, then you can write this using even less code:

        Sender _sender = new Sender();
        Receiver _receiver = new Receiver();

        Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber);

        // begin receiving the random number
        getRandomNumber.Start();

        // ... perform other tasks

        // accessing the Result property implicitly waits for the task to complete
        _receiver.TakeRandomNumber(getRandomNumber.Result);
like image 66
Dr. Wily's Apprentice Avatar answered Nov 10 '22 01:11

Dr. Wily's Apprentice


The "best" way to implement communication between two threads really depends on what needs to be communicated. Your example seems to be a classic producer/consumer problem. I would use a Synchronized Queue. Check out the MSDN documentation for Synchronized Collections. You can use the Queue.Synchronized method to get a synchronized wrapper for a Queue object. Then, have the producer thread call Enqueue() and the consumer call Dequeue().

like image 27
AngCaruso Avatar answered Nov 10 '22 00:11

AngCaruso