views:

126

answers:

4

I have a thread that connects to two network resources. Each time I attempt a connection, it can take 10 seconds for a reply.

void MyThread()
{
    //this takes ten seconds
    Resource r1 = MySystem.GetResource(ipAddress1);

    //this takes ten seconds
    Resource r2 = MySystem.GetResource(ipAddress2);

    //do stuff with ep1 and ep2
}

Total time is twenty seconds, but I'd really like it to take only ten seconds -- launching threads each time I call GetResource, receiving a reply and then joining each thread to return control.

What's the best way to do this? Launch two threads that each return a value? Anonymous methods that take references to local variables? My head is spinning. Code is appreciated.

A: 

Try this on MSDN: "Asynchronous programming using delegates."

http://msdn.microsoft.com/en-us/library/22t547yb.aspx

-Oisin

x0n
p.s. lots of code in the articles.
x0n
is there any example in particular?
MedicineMan
+1  A: 

The easiest way that occurs to me to do so is to parallelize one of the calls on a worker thread while having the main thread perform the second initialization and wait. The following snipet should help to illustrate:

ManualResetEvent r1Handle = new ManualResetEvent(false);
Resource         r1       = null;
Resource         r2       = null;

// Make the threadpool responsible for populating the 
// first resource.

ThreadPool.QueueUserWorkItem( (state) =>
{
  r1 = MySystem.GetResource(ipAddress1);

  // Set the wait handle to signal the main thread that
  // the work is complete.

  r1Handle.Set();
});

// Populate the second resource.

r2 = MySystem.GetResource(ipAddress2);

// Wait for the threadpool worker to finish.

r1Handle.WaitOne();

// ... Do more stuff

For a more detailed discussion of thread synchronization techniques, you may wish to visit the MSDN article on the topic: http://msdn.microsoft.com/en-us/library/ms173179.aspx

Jesse Squire
+4  A: 

How about

Resource r1 = null; // need to initialize, else compiler complains
Resource r2 = null;

ThreadStart ts1 = delegate {
    r1 = MySystem.GetResource(ipAddress1);
};
ThreadStart ts2 = delegate {
    r2 = MySystem.GetResource(ipAddress2);
};
Thread t1 = new Thread(ts1);
Thread t2 = new Thread(ts2);
t1.Start();
t2.Start();
// do some useful work here, while the threads do their thing...
t1.Join();
t2.Join();
// r1, r2 now setup

Short and sweet.

Vinay Sajip
I like this one too. I hope the community can help me figure out the best approach
MedicineMan
Out of curiosity, was there a reason why you chose to background both initializations? From what I can see, you'll now have the overhead of two background threads, while the main thread is idle and waiting for them to finish.
Jesse Squire
@Jesse Squire: It's just an illustration. For all I know, the real application could have N resources where N > 2. The main thread may have other stuff it wants to do before it does the `Join`s.
Vinay Sajip
+1  A: 

These are always fun questions to ponder, and of course there's multiple ways to solve it.

One approach that's worked well for me is to provide a callback method that each thread uses to pass back results and status. In the following example, I use a List to keep track of running threads and put the results in a Dictionary.

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

namespace ConsoleApplication1 { class Program { static Dictionary threadResults = new Dictionary(); static int threadMax = 2;

    static void Main(string[] args)
    {
        List<Thread> runningThreads = new List<Thread>();
        for (int i = 0; i < threadMax; i++)
        {
            Worker worker = new Worker();
            worker.Callback = new Worker.CallbackDelegate(ThreadDone);
            Thread workerThread = new Thread(worker.DoSomething);
            workerThread.IsBackground = true;
            runningThreads.Add(workerThread);
            workerThread.Start();
        }

        foreach (Thread thread in runningThreads) thread.Join();
    }

    public static void ThreadDone(int threadIdArg, object resultsArg)
    {
        threadResults[threadIdArg] = resultsArg;
    }
}


class Worker
{
    public delegate void CallbackDelegate(int threadIdArg, object resultArg);
    public CallbackDelegate Callback { get; set; }
    public void DoSomething()
    {
        // do your thing and put it into results
        object results = new object();
        int myThreadId = Thread.CurrentThread.ManagedThreadId;
        Callback(myThreadId, results);
    }
}

}

ebpower
seems a little complicated. Might be an interesting alternative if some of the other approaches don't work out
MedicineMan