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 Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multi-threading a timer?

Status
Not open for further replies.

RascaPR

Technical User
Oct 27, 2007
26
US
I have a timer which I want to run on a separate thread. Is this the proper way to start the TICK procedure of the timer?


Code:
        Thread PBThread;

        private void rdoPBBack_CheckedChanged(object sender, EventArgs e)
        {
            if (this.rdoPBBack.Checked == true)
            {
                Thread PBThread = new Thread(new ThreadStart(this.tmrPB.Start));
                this.tmrPB.Interval = 200;
                this.tmrPB.Enabled = true;
                PBThread.IsBackground = true;
                PBThread.Start();
            }
        }


        private void tmrPB_Tick(object sender, EventArgs e)
        {

            vblPBSelectedDistance = this.trkPB.Value;
            vblPBDistance = CalcDistance(GateLat, GateLon, Latitude, Longitude, "feet");

            if (this.vblPBDistance >= this.vblPBSelectedDistance)
            {
                this.btnEndFlight.Enabled = true;
                this.pbcontrol.Value = 3;
                this.tmrPB.Enabled = false;
                this.trkPB.Enabled = true;
                this.rdoPBBack.Enabled = true;
                this.rdoPBTailLeft.Enabled = true;
                this.rdoPBTailRight.Enabled = true;
                this.grpPushback.Visible = false;
                this.lblPBDistanceTravelled.Text = "";
            }
            else
            {
                this.trkPB.Enabled = false;
                this.rdoPBBack.Enabled = false;
                this.rdoPBTailLeft.Enabled = false;
                this.rdoPBTailRight.Enabled = false;
                this.btnEndFlight.Enabled = false;
                this.lblPBDistanceTravelled.Visible = true;
                this.lblPBDistanceTravelled.Text = vblPBDistance.ToString("F0").PadLeft(3, '0') + " FT";
            }
        }



Thanks for any help!
 
I assume you are using a System.Windows.Forms.Timer control. This control uses Windows Messages to launch the Tick event and as such the tick will always be on the UI thread. To get each tick to be on a separate thread you would do the following but be warned if the UI thread is busy when the tick happens you will not get an event fired.

Code:
private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());            
            timer.Interval = 1000;
            timer.Enabled = true;
            timer.Start();
        }        

        private void timer_Tick(object sender, EventArgs e)
        {
            Thread PBThread = new Thread(new ThreadStart(DoWork));
            PBThread.Start();
        }

        public static void DoWork() 
        {
            MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
            System.Threading.Thread.Sleep(2000);            
        }

It is however easier to get seperate threads using either the System.Threading.Timer class or the System.Timers.Timer class. And with these classes the event fires whether the UI is busy or not. You can use the System.Timers.Timer class like this:

Code:
private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Interval = 1000;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
            System.Threading.Thread.Sleep(2000);
        }

I have included the Sleep(2000) as threads are reused if they have finished and the sleep(2000) ensures this is not the case.

For a more thorough examination take a look at
Comparing the Timer Classes in the .NET Framework Class Library
on msdn.
 
Code:
this.btnEndFlight.Enabled = true;

As soon as you try to do things like this from a separate thread - your application will break. You can't touch a GUI item on the main thread from another thread.

Launching another GUI item such as a messagebox from another thread can be done but will cause your application to get complicated very quickly.

Consider doing the work you need in a separate thread (all calculations/data operations) and then when the thread is done - invoke a method on your main form to update the GUI items.

Code:
float vblPBDistance = 0f; //or whatever datatype this is

private void UpdateUI()
{
    if (this.vblPBDistance >= this.vblPBSelectedDistance)
            {
                this.btnEndFlight.Enabled = true;
                this.pbcontrol.Value = 3;
                this.tmrPB.Enabled = false;
                this.trkPB.Enabled = true;
                this.rdoPBBack.Enabled = true;
                this.rdoPBTailLeft.Enabled = true;
                this.rdoPBTailRight.Enabled = true;
                this.grpPushback.Visible = false;
                this.lblPBDistanceTravelled.Text = "";
            }
            else
            {
                this.trkPB.Enabled = false;
                this.rdoPBBack.Enabled = false;
                this.rdoPBTailLeft.Enabled = false;
                this.rdoPBTailRight.Enabled = false;
                this.btnEndFlight.Enabled = false;
                this.lblPBDistanceTravelled.Visible = true;
                this.lblPBDistanceTravelled.Text = vblPBDistance.ToString("F0").PadLeft(3, '0') + " FT";
            }
}

private void Timer1_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
   Thread t = new Thread(new ThreadStart(DoWork));
   t.Name = "Calculate Distance Thread";
   t.Start();
}

private void DoWork()
{
    vblPBDistance = CalcDistance(GateLat, GateLon, Latitude, Longitude, "feet"); //I hope you are not doing a switch statement based on "feet" - consider an Enum instead

    this.Invoke(UpdateUI, new object[]{});
}


Your threads now look like this

Main Thread
|
| DoWork - Separate Thread
|---------------|
| |
| |
| |
|<-------------- Work Complete - Invoke()
|
|
V

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top