Threadpool and Callbacks

Hi

could someone please point me to some simple code on threadpools and callbacks. The more I read on a google search, the more confused I get. I am a moderate level programmer at best, so easily confused unless it is kept simple.

I want to go off and get some external data, using a callback when the data comes back, multiple calls for different data simultaneously. Therefore, I believe what I need to use is a threadpool call with a callback that tells me when the request is responded to, such that I can then run a process to process the data being returned from the request, and such that the processor moves on whilst waiting for the response to come back.

I would appreciate it if I could be pointed to some simple code that creates a threadpool request to a method, passes parameters to the method, and allows processing of the resulting data that comes back.

I can't seem to find a simple code example to achieve same. I am doing this in another application with the backgroundworker, but believe I need to move to a threadppol here as there will be multiple requests happening simultaneously with differing response and process times. My application is a simple c# wondows application, although I am looking to do tihs with a c# console application to maximise speed.

Any advice would be appreciated

Ian
z488758Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Todd GerbertIT ConsultantCommented:
I'm not sure this will be helpful or not, I just happened to have it handy.

It uses a ThreadPool thread to do the ping'ing of IP addresses, and once a list of IP's that responded to the ping has been made, I used Dns.BeginGetHostEntry, which is an asynchronous method call and depends on the use of callbacks to notify me of completion.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;

class Program
{
	static long completedCounter = 0;
	static long errorCounter = 0;
	static long successCounter = 0;

	static object listLock = new object();
	static object consoleLock = new object();

	static List<IPAddress> aliveHosts = new List<IPAddress>();

	static void Main(string[] args)
	{
		Console.Write("Finding alive hosts...");

		// This just pings .1 through .254, for each network
		// 192.168.1.x, 192.168.2.x, 192.168.3.x and 192.168.4.x
		// This is my entire network, I can't make a test bigger'n this. ;)
		// Everytime a host responds to a ping, add it's address to
		// the aliveHosts list
		for (byte i = 1; i < 5; i++)
		{
			for (byte j = 1; j < 255; j++)
			{
				IPAddress ip = new IPAddress(new byte[] { 192, 168, i, j });
				ThreadPool.QueueUserWorkItem(PingProc, ip);
			}
		}

		do
		{
			Thread.Sleep(0);
		} while (Interlocked.Read(ref completedCounter) < 1016);

		// Reset the completedCounter
		completedCounter = 0;

		// Start timer here to check DNS performance
		Stopwatch stopwatch = new Stopwatch();
		stopwatch.Start();

		foreach (IPAddress ip in aliveHosts) // Only do lookups for hosts that are currently up
		{
			// Call GetHostEntry asynchronously - when GetHostEntry
			// finishes our GetHostEntryCallback method will be called
			Dns.BeginGetHostEntry(ip, new AsyncCallback(GetHostEntryCallback), ip);
		}

		do
		{
			// Wait until all pending GetHostEntry's finished
			// Thread.Sleep(0) won't sleep the thread, but will yield
			// processor time if another thread needs it
			Thread.Sleep(0);
		} while (Interlocked.Read(ref completedCounter) < aliveHosts.Count);
		stopwatch.Stop();

		Console.WriteLine("Resolved {0} IP addresses in {1} seconds.", aliveHosts.Count, stopwatch.Elapsed.TotalSeconds);
		Console.WriteLine("{0} IP addresses successfully resolved, {1} failed.", successCounter, errorCounter);
		Console.ReadKey();
	}

	static void PingProc(object arg)
	{
		IPAddress ip = (IPAddress)arg;
		Ping ping = new Ping();
		if (ping.Send(ip, 50).Status == IPStatus.Success)
			lock (listLock) aliveHosts.Add(ip); // This lock prevents different threads from trying to update the list at the same time
		Interlocked.Increment(ref completedCounter);
		lock (consoleLock) // This lock prevents threads from trying to write to the console at the same time
		{
			Console.CursorLeft = 22;
			Console.Write("{0} of 1016", Interlocked.Read(ref completedCounter));
		}
	}

	static void GetHostEntryCallback(IAsyncResult iar)
	{
		string hostName = null;
		try
		{
			IPHostEntry host = Dns.EndGetHostEntry(iar); // Gets the result of the asynchronous method
			hostName = host.HostName;
			Interlocked.Increment(ref successCounter);
		}
		catch (Exception ex)
		{
			hostName = ex.Message;
			Interlocked.Increment(ref errorCounter);
		}
		finally
		{
			lock (consoleLock) Console.WriteLine("{0} -> {1}", iar.AsyncState, hostName);
		}
		Interlocked.Increment(ref completedCounter); // Increment the counter everytime a lookup is done (success or failure)
		return;
	}
}

Open in new window



The "Begin..." methods are common in the .Net Framework, and you can use a similar methodology for your own methods - you just assign the function to a delegate, then you can call BeginInvoke on the delegate to execute your code in the background:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;

namespace ConsoleApplication2
{
	class Program
	{
		delegate string MyFuncDelegate(string message);

		static string modifiedMessage;

		static void Main(string[] args)
		{
			MyFuncDelegate myFuncVar = new MyFuncDelegate(MyFuncImplementation);

			// Start the function in background
			IAsyncResult iar = myFuncVar.BeginInvoke("Hello World", MyFuncCallback, myFuncVar);

			// Wait for it to finish
			iar.AsyncWaitHandle.WaitOne();

			Console.WriteLine(modifiedMessage);
			Console.ReadKey();
		}

		static string MyFuncImplementation(string Message)
		{
			return Message.ToUpper();
		}

		static void MyFuncCallback(IAsyncResult iar)
		{
			MyFuncDelegate originallyExecutedFunc = (MyFuncDelegate)iar.AsyncState;

			modifiedMessage = originallyExecutedFunc.EndInvoke(iar);

			// Often the above will be written more succinctly as:
			//modifiedMessage = ((MyFuncDelegate)iar.AsyncState).EndInvoke(iar);
		}
	}
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
z488758Author Commented:
Thanks, appreciate the assistance, will try and work with this
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.