This program is not thread safe and cause run time error in debug mode

T

Tony Johansson

Hello!

Below is a complete program that works fine in release mode but cause run
time errror in debug mode
because of "Cross-thread operation not valid: Control 'digital' accessed
from a thread
other than the thread it was created on."

The windows program below consist of these 4 classes
1. Program
2. Form
3. Clock
4 Ticker

Now to my questions.
Info the program below is a copy from a book called Visual studio 2005 from
Microsoft.
1. The first question is that the program below works fine in release mode
but cause
run time error in debug mode. So because of that I assume that the thread
handling must be different
between debug mode and release mode?
2.Is it always advisable to fix run time error of the kind that I have in
this program?
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?
4. Assume I have written a program and only run it in release mode because
it works as expected. In this case I will never
discover that there exist a problem with thead handling as in my example. So
is the solution to find problem
with thread to always run these program through the debugger?

The first class is the Program where the main is located
// *** Program ****
#region Using directives

using System;
using System.Collections.Generic;
using System.Windows.Forms;

#endregion

namespace Delegates
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
} //end class Program

The second class is the Form1 class
// Form1 start
#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

#endregion

namespace Delegates
{
partial class Form1 : Form
{
private Clock clock;
public Form1()
{
InitializeComponent();
clock = new Clock(digital);
}

private void start_Click(object sender, System.EventArgs e)
{ clock.Start(); }

private void stop_Click(object sender, System.EventArgs e)
{ clock.Stop(); }
} // end class Form1
}

Here I have the Form1.designer part
// ** Form1 Designer ***
Namespace Delegates
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.stop = new System.Windows.Forms.Button();
this.start = new System.Windows.Forms.Button();
this.digital = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// stop
//
this.stop.Location = new System.Drawing.Point(144, 67);
this.stop.Name = "stop";
this.stop.Size = new System.Drawing.Size(48, 23);
this.stop.TabIndex = 5;
this.stop.Text = "Stop";
this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
this.start.Location = new System.Drawing.Point(72, 67);
this.start.Name = "start";
this.start.Size = new System.Drawing.Size(56, 23);
this.start.TabIndex = 4;
this.start.Text = "Start";
this.start.Click += new System.EventHandler(this.start_Click);
//
// digital
//
this.digital.Enabled = false;
this.digital.Font = new System.Drawing.Font("Courier New",
20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.digital.Location = new System.Drawing.Point(56, 19);
this.digital.Name = "digital";
this.digital.Size = new System.Drawing.Size(152, 38);
this.digital.TabIndex = 3;
this.digital.Text = "04:11:34";
this.digital.TextAlign =
System.Windows.Forms.HorizontalAlignment.Center;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(264, 109);
this.Controls.Add(this.stop);
this.Controls.Add(this.start);
this.Controls.Add(this.digital);
this.Name = "Form1";
this.Text = "Digital Clock";
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.Button stop;
private System.Windows.Forms.Button start;
private System.Windows.Forms.TextBox digital;
}
}

The third class is the Clock class
// ** Clock ***
using System.Windows.Forms;

namespace Delegates
{
class Clock
{
private Ticker pulsed = new Ticker();
private TextBox display;

public Clock(TextBox display)
{ this.display = display; }

public void Start()
{ pulsed.tick += new Ticker.Tick(RefreshTime); }

public void Stop()
{ pulsed.tick -= new Ticker.Tick(RefreshTime); }

private void RefreshTime(int hh, int mm, int ss)
{ display.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm,
); }
}

//Start class Ticker
Namespace Delegates
{
using System.Timers;
class Ticker
{
public delegate void Tick(int hh, int mm, int ss);
public event Tick tick;
private Timer ticking = new Timer();

public Ticker()
{
ticking.Elapsed += new ElapsedEventHandler(OnTimedElapsed);
ticking.Interval = 1000;
ticking.Enabled = true;
}

private void Notify(int hours, int minutes, int seconds)
{ if (tick != null) tick(hours, minutes, seconds); }

private void OnTimedElapsed(object source, ElapsedEventArgs args)
{
int hh = args.SignalTime.Hour;
int mm = args.SignalTime.Minute;
int ss = args.SignalTime.Second;
Notify(hh, mm, ss); // call notify
}
}
} // end class Ticker
 
M

Marc Gravell

So because of that I assume that the thread handling must be different
between debug mode and release mode?
Yes; there is a debug assistant that detects this; there is also a
static property that can tweak this behavior (I suggest setting it to
*true*): http://msdn2.microsoft.com/en-us/li....control.checkforillegalcrossthreadcalls.aspx
2.Is it always advisable to fix run time error of the kind that I have in
this program?
Yes; you have a bug
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?

I'd need to look at it in debug (no time at this second), but normally
the answer is to (in any UI handler that is going to be fired by a non-
UI thread) use InvokeRequired / BeginInvoke / Invoke to pass control
to the UI thread. You can also use the sync-context. I'll see if I can
have a look later...

Marc
 
S

Sergey Zyuzin

Hello!

Below is a complete program that works fine in release mode but cause run
time errror in debug mode
because of "Cross-thread operation not valid: Control 'digital' accessed
from a thread
other than the thread it was created on."

The windows program below consist of these 4 classes
1. Program
2. Form
3. Clock
4 Ticker

Now to my questions.
Info the program below is a copy from a book called Visual studio 2005 from
Microsoft.
1. The first question is that the program below works fine in release mode
but cause
run time error in debug mode. So because of that I assume that the thread
handling must be different
between debug mode and release mode?
2.Is it always advisable to fix run time error of the kind that I have in
this program?
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?
4. Assume I have written a program and only run it in release mode because
it works as expected. In this case I will never
discover that there exist a problem with thead handling as in my example. So
is the solution to find problem
with thread to always run these program through the debugger?

The first class is the Program where the main is located
// *** Program ****
#region Using directives

using System;
using System.Collections.Generic;
using System.Windows.Forms;

#endregion

namespace Delegates
{
š š static class Program
š š {
š š š š /// <summary>
š š š š /// The main entry point for the application.
š š š š /// </summary>
š š š š [STAThread]
š š š š static void Main()
š š š š {
š š š š š š Application.EnableVisualStyles();
š š š š š š Application.Run(new Form1());
š š š š }
š š }

} //end class Program

The second class is the Form1 class
// Form1 start
#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

#endregion

namespace Delegates
{
š š partial class Form1 : Form
š š {
š š š š private Clock clock;
š š š š public Form1()
š š š š {
š š š š š š InitializeComponent();
š š š š š š clock = new Clock(digital);
š š š š }

š š š š private void start_Click(object sender, System.EventArgs e)
š š š š { clock.Start(); }

š š š š private void stop_Click(object sender, System.EventArgs e)
š š š š { clock.Stop(); }
š š } // end class Form1

}

Here I have the Form1.designer part
// ** Form1 Designer ***
Namespace Delegates
{
š š partial class Form1
š š {
š š š š /// <summary>
š š š š /// Required designer variable.
š š š š /// </summary>
š š š š private System.ComponentModel.IContainer components = null;

š š š š /// <summary>
š š š š /// Clean up any resources being used.
š š š š /// </summary>
š š š š protected override void Dispose(bool disposing)
š š š š {
š š š š š š if (disposing && (components != null))
š š š š š š {
š š š š š š š š components.Dispose();
š š š š š š }
š š š š š š base.Dispose(disposing);
š š š š }

š š š š #region Windows Form Designer generated code

š š š š /// <summary>
š š š š /// Required method for Designer support - do not modify
š š š š /// the contents of this method with the code editor.
š š š š /// </summary>
š š š š private void InitializeComponent()
š š š š {
š š š š š š this.stop = new System.Windows.Forms.Button();
š š š š š š this.start = new System.Windows.Forms.Button();
š š š š š š this.digital = new System.Windows.Forms.TextBox();
š š š š š š this.SuspendLayout();
//
// stop
//
š š š š š š this.stop.Location = new System.Drawing.Point(144, 67);
š š š š š š this.stop.Name = "stop";
š š š š š š this.stop.Size = new System.Drawing.Size(48, 23);
š š š š š š this.stop.TabIndex = 5;
š š š š š š this.stop.Text = "Stop";
š š š š š š this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
š š š š š š this.start.Location = new System.Drawing.Point(72, 67);
š š š š š š this.start.Name = "start";
š š š š š š this.start.Size = new System.Drawing.Size(56, 23);
š š š š š š this.start.TabIndex = 4;
š š š š š š this.start.Text = "Start";
š š š š š š this.start.Click += new System.EventHandler(this..start_Click);
//
// digital
//
š š š š š š this.digital.Enabled = false;
š š š š š š this.digital.Font = new System.Drawing.Font("Courier New",
20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
š š š š š š this.digital.Location = new System.Drawing.Point(56, 19);
š š š š š š this.digital.Name = "digital";
š š š š š š this.digital.Size = new System.Drawing.Size(152,38);
š š š š š š this.digital.TabIndex = 3;
š š š š š š this.digital.Text = "04:11:34";
š š š š š š this.digital.TextAlign =
System.Windows.Forms.HorizontalAlignment.Center;
//
// Form1
//
š š š š š š this.ClientSize = new System.Drawing.Size(264, 109);
š š š š š š this.Controls.Add(this.stop);
š š š š š š this.Controls.Add(this.start);
š š š š š š this.Controls.Add(this.digital);
š š š š š š this.Name = "Form1";
š š š š š š this.Text = "Digital Clock";
š š š š š š this.ResumeLayout(false);
š š š š š š this.PerformLayout();

š š š š }

š š š š #endregion

š š š š private System.Windows.Forms.Button šstop;
š š š š private System.Windows.Forms.Button šstart;
š š š š private System.Windows.Forms.TextBox digital;
š š }

}

The third class is the Clock class
// ** Clock ***
using System.Windows.Forms;

namespace Delegates
{
šclass Clock
š{
š š š š private Ticker špulsed = new Ticker();
š š š š private TextBox display;

š š š š public Clock(TextBox display)
š š š š { šthis.display = display; š}

š š š š public void Start()
š š š š{ pulsed.tick += new Ticker.Tick(RefreshTime); š }

š š š public void Stop()
š š š { pulsed.tick -= new Ticker.Tick(RefreshTime); }

š š š private void RefreshTime(int hh, int mm, int ss)
š š š { š display.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm,
); š }

}

//Start class Ticker
Namespace Delegates
{
š šusing System.Timers;
š šclass Ticker
š š{
š š š š public šdelegate void Tick(int hh, int mm, int ss);
š š š š public ševent Tick tick;
š š š š private Timer ticking = new Timer();

š š š špublic Ticker()
š š š š{
š š š š š š ticking.Elapsed += new ElapsedEventHandler(OnTimedElapsed);
š š š š š š ticking.Interval = 1000;
š š š š š š ticking.Enabled š= true;
š š š š}

š š š š šprivate void Notify(int hours, int minutes, int seconds)
š š š š š{ š if (tick != null) š tick(hours, minutes, seconds); š }

š š š š private void OnTimedElapsed(object source, ElapsedEventArgs args)
š š š š {
š š š š š š š š int hh = args.SignalTime.Hour;
š š š š š š š š int mm = args.SignalTime.Minute;
š š š š š š š š int ss = args.SignalTime.Second;
š š š š š š š š Notify(hh, mm, ss); // call notify
š š š š š}
š š}



} // end class Ticker- óËÒÙÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ -

- ðÏËÁÚÁÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ -

Hi Tony,

1. Thread handling should be the same in both release and debug modes.
However defects may show themselves differently in debug and
release.

3. As Marc said, you should set a control's properties from UI thread,
while
RefreshTime method is called from another thread when timer fires.

One option to fix the problem is to modify your RefreshData method in
the following way:

private void RefreshTime(int hh, int mm, int ss)
{
string text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm, ss);
display.BeginInvoke(new MethodInvoker(delegate { display.Text =
text; }));
}


4. Threading issues are usually difficult to find. They may appear
very rarely.
Many of multithreading issues can be found during stress/load
testing.
I usually start to suspect that there's something wrong with
multithreading if I
get errors that "can never occur".

Thanks,
Sergey
 
T

Tony Johansson

Hello!

You answered 3 of 4 questions.
I very interesting in how you would answer on the last fourth question?

//Tony
 
M

Marc Gravell

4: a bit trickier ;-p
According the the docs, release mode should be *more* paranoid, not
less:
<q>
Note that illegal cross-thread calls will always raise an exception
when an application is started outside the debugger.
</q>
However, threaded code is /always/ going to need a little caution, so
I gues the trick here is to learn to predict the issues and code
defensively. Not much of an answer, I'm afraid...

Marc
 
T

Tony Johansson

Hello!


If I have a control in the form that is accessed by a different thread then
the one that was used when the control was created
I get "Cross-thread operation not valid: Control 'digital' accessed
from a thread other than the thread it was created on." which this mail is
about
As I have written this error appear only in debug mode and not in release
mode.

So the debugger inform me that usage of thread is not correct.

Now to my question if this error is not corrected what would the
consequences be ?
What symptom could I get when this program is put into production because of
incorrect usage of threads.


//Tony


"Sergey Zyuzin" <[email protected]> skrev i meddelandet
Hello!

Below is a complete program that works fine in release mode but cause run
time errror in debug mode
because of "Cross-thread operation not valid: Control 'digital' accessed
from a thread
other than the thread it was created on."

The windows program below consist of these 4 classes
1. Program
2. Form
3. Clock
4 Ticker

Now to my questions.
Info the program below is a copy from a book called Visual studio 2005
from
Microsoft.
1. The first question is that the program below works fine in release mode
but cause
run time error in debug mode. So because of that I assume that the thread
handling must be different
between debug mode and release mode?
2.Is it always advisable to fix run time error of the kind that I have in
this program?
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?
4. Assume I have written a program and only run it in release mode because
it works as expected. In this case I will never
discover that there exist a problem with thead handling as in my example.
So
is the solution to find problem
with thread to always run these program through the debugger?

The first class is the Program where the main is located
// *** Program ****
#region Using directives

using System;
using System.Collections.Generic;
using System.Windows.Forms;

#endregion

namespace Delegates
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}

} //end class Program

The second class is the Form1 class
// Form1 start
#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

#endregion

namespace Delegates
{
partial class Form1 : Form
{
private Clock clock;
public Form1()
{
InitializeComponent();
clock = new Clock(digital);
}

private void start_Click(object sender, System.EventArgs e)
{ clock.Start(); }

private void stop_Click(object sender, System.EventArgs e)
{ clock.Stop(); }
} // end class Form1

}

Here I have the Form1.designer part
// ** Form1 Designer ***
Namespace Delegates
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.stop = new System.Windows.Forms.Button();
this.start = new System.Windows.Forms.Button();
this.digital = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// stop
//
this.stop.Location = new System.Drawing.Point(144, 67);
this.stop.Name = "stop";
this.stop.Size = new System.Drawing.Size(48, 23);
this.stop.TabIndex = 5;
this.stop.Text = "Stop";
this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
this.start.Location = new System.Drawing.Point(72, 67);
this.start.Name = "start";
this.start.Size = new System.Drawing.Size(56, 23);
this.start.TabIndex = 4;
this.start.Text = "Start";
this.start.Click += new System.EventHandler(this.start_Click);
//
// digital
//
this.digital.Enabled = false;
this.digital.Font = new System.Drawing.Font("Courier New",
20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.digital.Location = new System.Drawing.Point(56, 19);
this.digital.Name = "digital";
this.digital.Size = new System.Drawing.Size(152, 38);
this.digital.TabIndex = 3;
this.digital.Text = "04:11:34";
this.digital.TextAlign =
System.Windows.Forms.HorizontalAlignment.Center;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(264, 109);
this.Controls.Add(this.stop);
this.Controls.Add(this.start);
this.Controls.Add(this.digital);
this.Name = "Form1";
this.Text = "Digital Clock";
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.Button stop;
private System.Windows.Forms.Button start;
private System.Windows.Forms.TextBox digital;
}

}

The third class is the Clock class
// ** Clock ***
using System.Windows.Forms;

namespace Delegates
{
class Clock
{
private Ticker pulsed = new Ticker();
private TextBox display;

public Clock(TextBox display)
{ this.display = display; }

public void Start()
{ pulsed.tick += new Ticker.Tick(RefreshTime); }

public void Stop()
{ pulsed.tick -= new Ticker.Tick(RefreshTime); }

private void RefreshTime(int hh, int mm, int ss)
{ display.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm,
); }

}

//Start class Ticker
Namespace Delegates
{
using System.Timers;
class Ticker
{
public delegate void Tick(int hh, int mm, int ss);
public event Tick tick;
private Timer ticking = new Timer();

public Ticker()
{
ticking.Elapsed += new ElapsedEventHandler(OnTimedElapsed);
ticking.Interval = 1000;
ticking.Enabled = true;
}

private void Notify(int hours, int minutes, int seconds)
{ if (tick != null) tick(hours, minutes, seconds); }

private void OnTimedElapsed(object source, ElapsedEventArgs args)
{
int hh = args.SignalTime.Hour;
int mm = args.SignalTime.Minute;
int ss = args.SignalTime.Second;
Notify(hh, mm, ss); // call notify
}
}



} // end class Ticker- óËÒÙÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ -

- ðÏËÁÚÁÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ -

Hi Tony,

1. Thread handling should be the same in both release and debug modes.
However defects may show themselves differently in debug and
release.

3. As Marc said, you should set a control's properties from UI thread,
while
RefreshTime method is called from another thread when timer fires.

One option to fix the problem is to modify your RefreshData method in
the following way:

private void RefreshTime(int hh, int mm, int ss)
{
string text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm, ss);
display.BeginInvoke(new MethodInvoker(delegate { display.Text =
text; }));
}


4. Threading issues are usually difficult to find. They may appear
very rarely.
Many of multithreading issues can be found during stress/load
testing.
I usually start to suspect that there's something wrong with
multithreading if I
get errors that "can never occur".

Thanks,
Sergey
 
S

Sergey Zyuzin

Hello!

If I have a control in the form that is accessed by a different thread then
the one that was used when the control was created
I get "Cross-thread operation not valid: Control 'digital' accessed
from a thread other than the thread it was created on." which this mail is
about
As I have written this error appear only in debug mode and not in release
mode.

So the debugger inform me that usage of thread is not correct.

Now to my question if this error is not corrected what would the
consequences be ?
What symptom could I get when this program is put into production because of
incorrect usage of threads.

//Tony

"Sergey Zyuzin" <[email protected]> skrev i meddelandet
Below is a complete program that works fine in release mode but cause run
time errror in debug mode
because of "Cross-thread operation not valid: Control 'digital' accessed
from a thread
other than the thread it was created on."
The windows program below consist of these 4 classes
1. Program
2. Form
3. Clock
4 Ticker
Now to my questions.
Info the program below is a copy from a book called Visual studio 2005
from
Microsoft.
1. The first question is that the program below works fine in release mode
but cause
run time error in debug mode. So because of that I assume that the thread
handling must be different
between debug mode and release mode?
2.Is it always advisable to fix run time error of the kind that I have in
this program?
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?
4. Assume I have written a program and only run it in release mode because
it works as expected. In this case I will never
discover that there exist a problem with thead handling as in my example..
So
is the solution to find problem
with thread to always run these program through the debugger?
The first class is the Program where the main is located
// *** Program ****
#region Using directives
using System;
using System.Collections.Generic;
using System.Windows.Forms;
#endregion

namespace Delegates
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
} //end class Program
The second class is the Form1 class
// Form1 start
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace Delegates
{
partial class Form1 : Form
{
private Clock clock;
public Form1()
{
InitializeComponent();
clock = new Clock(digital);
}
private void start_Click(object sender, System.EventArgs e)
{ clock.Start(); }
private void stop_Click(object sender, System.EventArgs e)
{ clock.Stop(); }
} // end class Form1

Here I have the Form1.designer part
// ** Form1 Designer ***
Namespace Delegates
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.stop = new System.Windows.Forms.Button();
this.start = new System.Windows.Forms.Button();
this.digital = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// stop
//
this.stop.Location = new System.Drawing.Point(144, 67);
this.stop.Name = "stop";
this.stop.Size = new System.Drawing.Size(48, 23);
this.stop.TabIndex = 5;
this.stop.Text = "Stop";
this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
this.start.Location = new System.Drawing.Point(72, 67);
this.start.Name = "start";
this.start.Size = new System.Drawing.Size(56, 23);
this.start.TabIndex = 4;
this.start.Text = "Start";
this.start.Click += new System.EventHandler(this.start_Click);
//
// digital
//
this.digital.Enabled = false;
this.digital.Font = new System.Drawing.Font("Courier New",
20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.digital.Location = new System.Drawing.Point(56, 19);
this.digital.Name = "digital";
this.digital.Size = new System.Drawing.Size(152, 38);
this.digital.TabIndex = 3;
this.digital.Text = "04:11:34";
this.digital.TextAlign =
System.Windows.Forms.HorizontalAlignment.Center;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(264, 109);
this.Controls.Add(this.stop);
this.Controls.Add(this.start);
this.Controls.Add(this.digital);
this.Name = "Form1";
this.Text = "Digital Clock";
this.ResumeLayout(false);
this.PerformLayout();


private System.Windows.Forms.Button stop;
private System.Windows.Forms.Button start;
private System.Windows.Forms.TextBox digital;
}

The third class is the Clock class
// ** Clock ***
using System.Windows.Forms;
namespace Delegates
{
class Clock
{
private Ticker pulsed = new Ticker();
private TextBox display;
public Clock(TextBox display)
{ this.display = display; }
public void Start()
{ pulsed.tick += new Ticker.Tick(RefreshTime); }
public void Stop()
{ pulsed.tick -= new Ticker.Tick(RefreshTime); }
private void RefreshTime(int hh, int mm, int ss)
{ display.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm,
); }

//Start class Ticker
Namespace Delegates
{
using System.Timers;
class Ticker
{
public delegate void Tick(int hh, int mm, int ss);
public event Tick tick;
private Timer ticking = new Timer();
public Ticker()
{
ticking.Elapsed += new ElapsedEventHandler(OnTimedElapsed);
ticking.Interval = 1000;
ticking.Enabled = true;
}
private void Notify(int hours, int minutes, int seconds)
{ if (tick != null) tick(hours, minutes, seconds); }
private void OnTimedElapsed(object source, ElapsedEventArgs args)
{
int hh = args.SignalTime.Hour;
int mm = args.SignalTime.Minute;
int ss = args.SignalTime.Second;
Notify(hh, mm, ss); // call notify
}
}
} // end class Ticker- óËÒÙÔØ ÃÉÔÉÒÕÅÍÙÊÔÅËÓÔ -
- ðÏËÁÚÁÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ -

Hi Tony,

1. Thread handling should be the same in both release and debug modes.
    However defects may show themselves differently in debug and
release.

3. As Marc said, you should set a control's properties from UI thread,
while
RefreshTime method is called from another thread when timer fires.

One option to fix the problem is to modify your RefreshData method in
the following way:

private void RefreshTime(int hh, int mm, int ss)
{
     string text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm, ss);
     display.BeginInvoke(new MethodInvoker(delegate { display.Text =
text; }));

}

4. Threading issues are usually difficult to find. They may appear
very rarely.
    Many of multithreading issues can be found during stress/load
testing.
    I usually start to suspect that there's something wrong with
multithreading if I
    get errors that "can never occur".

Thanks,
Sergey- Hide quoted text -

- Show quoted text -

I'm afraid I can't tell exactly what symptoms you'll get in this case,
because I've never experienced it and in all articles I've read I
didn't see what could happen if you didn't use Control.Invoke.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top