Solved

Threadpool and Callbacks

Posted on 2011-03-20
2
939 Views
Last Modified: 2012-05-11
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
0
Comment
Question by:z488758
2 Comments
 
LVL 33

Accepted Solution

by:
Todd Gerbert earned 500 total points
ID: 35180957
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
 

Author Closing Comment

by:z488758
ID: 35186787
Thanks, appreciate the assistance, will try and work with this
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question