Avicena00
Avicena00

Reputation: 365

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

Upvotes: 14

Views: 46643

Answers (5)

Dr. Wily's Apprentice
Dr. Wily's Apprentice

Reputation: 10280

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

Upvotes: 10

AngCaruso
AngCaruso

Reputation: 570

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().

Upvotes: 2

Cole W
Cole W

Reputation: 15293

If all you are doing is generating a random number in the one thread I would probably create a thread safe object that does this instead.

lock(syncRoot)
{
    myCurrentRandom = Generate();
    return myCurrentRandom;
}

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1499740

If you're using .NET 4, I would suggest using a higher level abstraction: Task<TResult>. Your first thread can schedule the task (which may end up creating a thread, or be scheduled on an existing task-handling thread) and can then check for status, block for the result etc as it sees fit.

If you want to do more than a one-shot task, you may want to use a producer/consumer queue - again, .NET 4 helps with that via BlockingCollection<T>.

Upvotes: 23

Mithrandir
Mithrandir

Reputation: 25337

You will need some kind of resource (list, queue, etc.) shared between sender and receiver. And you will have to synchronize the access to this resource, otherwise you will not be able to pass data between the threads.

Upvotes: 4

Related Questions