HectorDZJ
HectorDZJ

Reputation: 43

Calling several timers with the original values from when they were created?

I am working on an application that queries servers for its status via WMI, I was asked to make it automatically recurrent and that it can queue the queries to get the statuses of several servers every so often. The problem I am having is that the values that are established when the first timer is created have changed by the time the socond one is (like server name, and query type). This is a portion of the code:

public System.Threading.Timer[] schedquery = new System.Threading.Timer[10];
private void button1_Click(object sender, EventArgs e)
    {
        schedquery[C3MonitorApp.globalVars.tmrArray] = new System.Threading.Timer(writeLog);
        schedValues.schedTurns = 120 / schedValues.schedTimer;
        schedquery[C3MonitorApp.globalVars.tmrArray].Change(1000, 0);
        C3MonitorApp.globalVars.tmrArray++;
    }

    public void writeLog(object state)
    {
        //do queries and write results to file then check if the timer
        //has done certain amount of loops and dispose or restart
        schedValues.schedTurnCounter++;
        if (schedValues.schedTurnCounter == schedValues.schedTurns)
        {
            this.Dispose();
        }
        else
        {

            System.Threading.Timer t = (System.Threading.Timer)state;
            t.Change(1000 * 60 * schedValues.schedTimer, 0);

        }
    }

The write log function obtains the server name and query type from a public class, so I want this values like the server name be stored somehow so the timer runs the callback using the original values instead of the ones used to create the second, third or fourth timer.

Regards.

Upvotes: 0

Views: 76

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 134005

The state object passed to the timer is the state argument you pass to the constructor. I'm a little surprised that your code works at all, considering that your code doesn't pass a state argument. Meaning that the code in your else should fail with an invalid cast or null reference exception.

It's difficult to say for sure because your question is a little vague, but I think what you want is to create a state object and pass that in the constructor. For example:

class TimerState
{
    public string ServerName { get; set; }
    public string QueryType { get; set; }
    public int TimerIndex { get; set; }
}

private void button1_Click(object sender, EventArgs e)
{
    schedValues.schedTurns = 120 / schedValues.schedTimer;
    var stateObj = new TimerState
        { ServerName = "foo", QueryType = "bar", TimerIndex = C3MonitorApp.globalVars.tmrArray };
    schedquery[C3MonitorApp.globalVars.tmrArray] =
        new System.Threading.Timer(writeLog, stateObj, 1000, 0);
    C3MonitorApp.globalVars.tmrArray++;
}

And change your writeLog:

public void writeLog(object state)
{
    TimerState stateObj = (TimerState)state;
    Timer t = schedquery[stateObj.TimerIndex];

    //do queries and write results to file then check if the timer
    //has done certain amount of loops and dispose or restart
    schedValues.schedTurnCounter++;
    if (schedValues.schedTurnCounter == schedValues.schedTurns)
    {
        t.Dispose();
    }
    else
    {
        t.Change(1000 * 60 * schedValues.schedTimer, 0);
    }
}

I'm pretty sure you don't want to dispose this. You want to dispose the timer, as I show here.

I'm likely missing something about the specifics of your application, but the above will give you the general idea.

Upvotes: 1

Related Questions