Solved

Threadpool and Callbacks

Posted on 2011-03-20
2
925 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

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

746 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now