Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Can someone explain what this line does?

Status
Not open for further replies.

jwarmuth

IS-IT--Management
Sep 22, 2001
151
CA
I've come across some syntax that has never been explained to me in any book, tutorial, or reference doc and it's pissing me off (to say the least!).

This is the example code from MS on using the Threading.Timer object.

Code:
using System;
using System.Threading;

class TimerExampleState 
{
   public int counter = 0;
   public Timer tmr;
}

class App 
{
   public static void Main()
   {
   TimerExampleState s = new TimerExampleState();

   // Create the delegate that invokes methods for the timer.
   TimerCallback timerDelegate = new TimerCallback(CheckStatus);

   // Create a timer that waits one second, then invokes every second.
   Timer timer = new Timer(timerDelegate, s,1000, 1000);
    
   // Keep a handle to the timer, so it can be disposed.
   s.tmr = timer;

   // The main thread does nothing until the timer is disposed.
   while(s.tmr != null)
         Thread.Sleep(0);
   Console.WriteLine("Timer example done.");
   }
   // The following method is called by the timer's delegate.

   static void CheckStatus(Object state)
   {
   TimerExampleState s =(TimerExampleState)state;
   s.counter++;
   Console.WriteLine("{0} Checking Status {1}.",DateTime.Now.TimeOfDay, s.counter);
   if(s.counter == 5)
      {
      // Shorten the period. Wait 10 seconds to restart the timer.
      (s.tmr).Change(10000,100);
      Console.WriteLine("changed...");
      }
   if(s.counter == 10)
      {
      Console.WriteLine("disposing of timer...");
      s.tmr.Dispose();
      s.tmr = null;
      }
   }
}

The line I don't understand is:
TimerExampleState s =(TimerExampleState)state;

I just dont' get where 'state' enters into the picture. When the callback calls the CheckStatus method, no args are passed, so what is this 'state' thing all about? And why is the syntax in that manner (parenthesis before the 'state')?

Jeff W.
MCSE, CNE
 
by putting (TimerExampleState)state - you are casting state to a type of TimerExampleState class.

Without this, the class is considered just an object and you cannot access its functions because .net doesn't know what kind of object it is.

Hope that makes sense.
 
When you called this line:
Code:
new Timer(timerDelegate, s,1000, 1000);
you're passing it a reference to s.

The Timer constructor has that parameter defined as a object so that a programmer can pass an instance of a class of any type to the timer callback function -- in your case, named [tt]CheckStatus[/tt]. The .net runtime holds onto it for you, and hands it back to you when the timer expires.

You'll see this same pattern in all of the Begin* methods in the framework (BeginInvoke, BeginSend, etc), which return an object that implements IAsyncResult. In the trivial examples in the Socket communications area, they usually just pass the listening Socket to the callback, but in a real app, you'd have an object which holds the state information that the callback method needs.

You're probably asking, why doesn't the callback just access stuff like normal, and the answer is that it's not running on your thread -- it's typically running on a thread from the system thread pool. So accessing something outside the callstack rooted at the callback method would be a big no-no (or at a minimum, require a lot of locking to make it thread-safe).

Chip H.


____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
Okay, I'm trying really hard to understand this Threading.Timer object, so I wrote my own little app to play with.

Code:
using System;
using System.Threading;


namespace Learn2ThreadingTimer
{

	class Class1
	{

		[STAThread]
		static void Main(string[] args)
		{
			Animal myDog = new Animal();
			
			TimerCallback myCallback = new TimerCallback(myDog.Run);

			//create Timer
			Timer tmr = new Timer(myCallback,myDog, 0, 1);
			myDog.aniTimer = tmr;
			while(myDog.aniTimer != null)
				Thread.Sleep(0);
		}
	}

	class Animal
	{
		int m_iSteps = 0;
		public Timer aniTimer;
		
		public void Run(Object stateInfo)
		{
			//Animal myDog = (Animal)stateInfo;
			m_iSteps++;
			Console.WriteLine(m_iSteps.ToString());

			if (m_iSteps == 10)
			{
				aniTimer.Dispose();
				Console.WriteLine("Timer object disposed");
			}
		}

		public int Steps
		{
			get
			{
				return m_iSteps;
			}
			set
			{
				m_iSteps = value;
			}
		}

	}
}

What I've noticed, is that the program runs the same whether or not the casting line is rem'd out. I was under the impression it was a required statement.

I'm obviously missing something here, although I feel like I'm getting closer to understanding. I appreciate the help btw!

Jeff W.
MCSE, CNE
 
Code:
 public void Run(Object stateInfo)
        {
            //Animal myDog = (Animal)stateInfo;
            m_iSteps++;
            Console.WriteLine(m_iSteps.ToString());

            if (m_iSteps == 10)
            {
                aniTimer.Dispose();
                Console.WriteLine("Timer object disposed");
            }
        }
Commenting out that line is OK because you aren't using the variable [tt]myDog[/tt] anywhere in that method.

The purpose of the stateInfo is to provide a way to pass information into the callback method ([tt]Run[/tt] in your sample). This is because when [tt]Run[/tt] gets called, it's running on a different thread than the rest of your code.

Normally, accessing a variable from a different thread means that you have to implement locks, etc. to prevent concurrent access problems. But by passing you this variable as a method parameter, it's on your local stackframe, and there's no need for a lock -- which makes things much easier for you.

Note that the variable that you specify doesn't have to be of type [tt]Animal[/tt] -- it can be anything that derives from [tt]System.Object[/tt] -- meaning anything at all. So you could pass a [tt]Barn[/tt] object which contains several [tt]Animal[/tt]s just as easily.

Chip H.

____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top