Using multiple timers in Visual Studio 2010 C#
-
14. dubna 2012 23:12
Hello!
I am an Electrical Engineering student doing my Senior Year Project. Part of my project requires a Windows Form Application that does 3 things:
1) GUI for user interactions
2) Communications using RF modules
3) Data Acquisition through mic interface
My focus is on the 1 and 2 though eventually 3 (which is being done by a group partner) will be integrated with 1 & 2. Now, my application requires the use of multiple timers, specifically as follows:
private void timer1_Tick(object sender, EventArgs e) //called every 1 ms { //some code that takes less than 1 ms to execute } private void timer2_Tick(object sender, EventArgs e) //called every 25 ms { //some code that takes less than 1 ms to execute } private void timer3_Tick(object sender, EventArgs e) //called every 30 seconds { //some code that takes 2-5 seconds to execute }
At the moment I am not using timer3 (that is being used by my partner in another form application). I used system.windows.forms.timers for the timers though recently upon finding out that system.timers.timer is more accurate I used that. Now, the problem is that timer3 has a code that takes 2-5 s to execute. When I will integrate that code with my own, will there be any problems? Specifically, for e.g. will timer1 cause that code execution of timer3 to be blocked since it is called every 1 ms. is there way to avoid this without disabling timer 1 and 2 (through the use of threads maybe)?
Thank You!
Všechny reakce
-
15. dubna 2012 0:11Moderátor
The System.Timer.Timer class runs its' callback on the thread that owns the handle to the object assigned to the SynchronizingObject property. This will usually be a WinForm, so the callback will run on the UI thread.
http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
That Timer is most useful when you wish to run the callback one different threads from one callback to another callback. By changing the property, you can alter which thread runs the callback. It is also tricky and difficult to use. I never use it.
The System.Threading.Timer class runs its' callback on a random thread from the ThreadPool. You are not guaranteed to always get the same thread.
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
It is very precise. I recommend that you use the Threading timer over the Timers timer. It has a resolution of 1 millisecond.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
http://thesharpercoder.blogspot.com/
- Upravený Rudedog2MVP, Moderator 15. dubna 2012 0:14
- Navržen jako odpověď AceInfinityMVP 15. dubna 2012 5:01
-
15. dubna 2012 5:02That's a great piece of information Rudedog2. I would agree here, i've seen more precise results when using the System.Threading.Timer as well.
If a post helps you in any way or solves your particular issue, please remember to use the Propose As Answer option or Vote As Helpful
Visit the Forum: TechLifeForum -
15. dubna 2012 16:55
thanks for the prompt reply but can you specifically address this issue:
"timer3 has a code that takes 2-5 s to execute. will timer1 (that is called every 1 ms) cause the code execution of timer3 to be blocked since it is called every 1 ms. is there way to avoid this without disabling timer 1 and 2 (through the use of threads maybe)? "
-
15. dubna 2012 17:23
They have answered you :)
you should use System.Threading.Timer instead of System.Timer.Timer
Then every timer will run on random thread then you will not have blocking.
- Upravený Abed ElAzeem Bukhari 15. dubna 2012 17:23
-
15. dubna 2012 17:54Moderátor
thanks for the prompt reply but can you specifically address this issue:
"timer3 has a code that takes 2-5 s to execute. will timer1 (that is called every 1 ms) cause the code execution of timer3 to be blocked since it is called every 1 ms. is there way to avoid this without disabling timer 1 and 2 (through the use of threads maybe)? "
It depends upon what you assign to the Timer.Timer.SynchronizingObject. The object assigned to that property needs to implement the following interface because this is the type assigned to that property.
ISynchronizeInvoke Interface (System.ComponentModel)
I know of only one object in the Base Class Library that implements that interface, System.Windows.Forms.Control. The callback to the Timer will run on the thread that created the handle for the object instance that you assign to the property. In other words, the callback will run on the UI thread and will block it.
Leaving the SynchronizingObject property will cause the the callback to be executed on a random thread from the ThreadPool. Once that callback finishes executing like that, the process will most likely be "lost" and unable to find its' way back to the UI thread because it lacks Context to find the UI thread. If it finds its' way back, consider it a chance stroke of luck.
I cannot say whether or not it will block the handler/callback for your timer3 because I do not know its' type. I will repeat my suggestion to use the Threading.Timer class because it is very accurate. A 1 mS interval is extremely tight, though. I am sure you know what accurate to +/- 1 mS means. An interval that short raises the spectre of reentrance issues.
I think you said that you are running two timers at that interval. Be aware that all of the timers will run on the same thread, further consuming more CPU time. It may be best to run a single watchdog timer that invokes calls to the appropriate code at appropriate intervals. A single timer will also simplify the task of synchronizing the tasks tremendously.
Perhaps an abstract base class that defines a WatchdogTask would be helpful.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
http://thesharpercoder.blogspot.com/
EDIT
public abstract class WatchdogTask<T> : IDisposable where T: EventArgs { protected int currentTick; public int Interval { get; set; } protected EventHandler<T> callback; protected WatchdogTask(EventHandler<T> callback, int interval) { this.currentTick = 0; this.callback = callback; this.Interval = interval; } public virtual void Tick() { this.currentTick += 1; if ( this.currentTick == this.Interval ) { this.currentTick = 0; this.OnCallback(this.GetEventArgs()); } } protected virtual void OnCallback(T args) { this.callback.Invoke(this, args); } public abstract T GetEventArgs(); public virtual void Dispose() { this.callback = null; } }Inherit this class with a custom EventArgs class. Pass a callback delegate to the constructor and an Interval. On every Tick of the Watchdog timer, call the tick method on a derived object instance. When the set number of ticks is reached, a callback is made to the delegate that was passed into the constructor. Notice that consuming classes must implement the GetEventArgs method.
Do you know how to setup and use the Threading timer?
- Upravený Rudedog2MVP, Moderator 15. dubna 2012 18:52
-
15. dubna 2012 18:31If the 1ms timer is to control "3) Data Acquisition through mic interface", you should recode that part of your program to use multimedia objects that can precisely sample the sound card input. If the 25ms timer is getting data for use by the UI, it should be a System.Timers.Timer. If it doesn't interact with the UI, use a System.Threading.Timer. The 30 seconds timer type depends upon whether the UI can be blocked or not.
-
15. dubna 2012 18:32
OK thanks....I will try them...a couple of other things:
1) what if I use normal (windows form ) timers and create threads in the callback function (which run the actual call back function) e.g:
private void Timer1Code() { //code that was previously in Timer1_Tick } private void Timer1_Tick(object sender, EventArgs e) { Thread Timer1Thread = new Thread(Timer1Code); Timer1Thread.Start(); }
2) what if I just run timer3 as a separate System.Threading.Timer while keeping the other timers (system.windows.forms.timers or system.timers.timer) tied to the main UI thread (as I haven't had any problem with that yet)?
-
15. dubna 2012 18:41
If you can do this and the results are acceptable, your posted timings are inconsequntial. A timer that runs on the UI thread is queued and runs somewhat randomly, depending upon other activity on the thread.OK thanks....I will try them...a couple of other things:
1) what if I use normal (windows form ) timers and create threads in the callback function (which run the actual call back function) e.g:
private void Timer1Code() { //code that was previously in Timer1_Tick } private void Timer1_Tick(object sender, EventArgs e) { Thread Timer1Thread = new Thread(Timer1Code); Timer1Thread.Start(); }
2) what if I just run timer3 as a separate System.Threading.Timer while keeping the other timers (system.windows.forms.timers or system.timers.timer) tied to the main UI thread (as I haven't had any problem with that yet)?
-
15. dubna 2012 18:58ModerátorThe Forms timer has an accuracy of +/- 50 mS.
Mark the best replies as answers. "Fooling computers since 1971."
-
15. dubna 2012 19:05the 1ms timer is used to check the serialport buffer for unread data, the 25ms timer is used to refresh the UI, and the 30s timer is used for data acquisition i.e. after every 30s data is acquired for 2-5s (I do not have the exact details about how the data is acquired, but my partner is using a library to do that). the UI and communications timer both interact with each other.
-
15. dubna 2012 19:07
"The Forms timer has an accuracy of +/- 50 mS."
That's an old wives tale. Somehow that got in the documentation in the Windows 95 time frame and it stuck. It's accuracy depends upon other activity on the thread. If there is no other activity on the thread, the CPU is a modern multicore and the OS is Win7, it can tick at 1ms intervals accurately.
-
15. dubna 2012 19:11
Do you know how to setup and use the Threading timer?
No, but I hope I can learn it relatively easily on the MSDN library. One thing that I should like to point out is that I am using many variables and flags, and these get passed in between timers. I tried the following for all timers (used normal (windows form ) timers and created threads in the callback function (which run the actual call back function) e.g:):
private void Timer1Code() { //code that was previously in Timer1_Tick } private void Timer1_Tick(object sender, EventArgs e) { Thread Timer1Thread = new Thread(Timer1Code); Timer1Thread.Start(); }However, my application would crash instantly because of some reference to null issue which I take to be as a result of many threads accessing/modifying the variable in question....so I would like to avoid this issue otherwise I would have days of re-coding in front of me (which I'd like to avoid at this stage of my application).
-
15. dubna 2012 19:13
the 1ms timer is used to check the serialport buffer for unread data, the 25ms timer is used to refresh the UI, and the 30s timer is used for data acquisition i.e. after every 30s data is acquired for 2-5s (I do not have the exact details about how the data is acquired, but my partner is using a library to do that). the UI and communications timer both interact with each other.
The 1ms timer is superfluous. Use the DataReceived event. This post explains why none of the timings are very important. I might use a sleeping BackgroundWorker for the 30 second timer.- Označen jako odpověď champion7891 17. dubna 2012 1:45
-
15. dubna 2012 21:29
Ok I will try that and post results in some time, but please tell me, if by using the DataReceived event instead of the 1 ms timer, would my timer3 (30s) code get interrupted?Use the DataReceived event. This post explains why none of the timings are very important. I might use a sleeping BackgroundWorker for the 30 second timer.
-
15. dubna 2012 21:32
"Ok I will try that and post results in some time, but please tell me, if by using the DataReceived event instead of the 1 ms timer, would my timer3 (30s) code get interrupted?"
The DataReceived event runs on its own thread.
- Označen jako odpověď champion7891 17. dubna 2012 1:45
-
15. dubna 2012 23:15
Hey thanks a lot for that DataReceived tip....but I am encountering some problems with my code which I hope you may help me solve. Specifically, upon reading the serial port buffer, I update the GUI by updating a ListBox called DevicesBox. Previously, I did this as:
{ //DevicesNamesList gets updated here gui.DevicesBox.DataSource = null; gui.DevicesBox.DataSource = gui.DevicesNamesList; gui.DevicesBox.Refresh(); }
However, now I get this error : "Cross-thread operation not valid: Control 'DevicesBox' accessed from a thread other than the thread it was created on."
I understand that this happens because DataReceived method creates its own thread and tries to access the main UI thread. Can you suggest a way to do this while avoiding the error.
-
16. dubna 2012 0:29
Start in help at InvokeRequired. Read and follow links until you throroghly understand what you are doing. You'll need to know this for other parts of your program also. To understand Windows threading, you should understand the windows event pattern sending and posting messages.to message pumps/
-
16. dubna 2012 12:52
Hello! I did what you suggested but the articles on MSDN is a bit sparse on examples. Any ways I created a small application which has that cross thread issue that I hope you may help me resolve
Basically, whenever there is data to be read on the serial port, the BindingList tied to the listbox is updated, causing its event handler to run, which should refresh the listbox but the cross thread error occurs. I'd be grateful if you could insert some snippet that would resolve the issue. Thanks!
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.IO.Ports; using System.Collections; using System.Management; using System.Threading; using System.Runtime.InteropServices; using Microsoft.Win32; namespace testListBox { /*Class1 is used to automatically find and open a serial port, and has an event handler for whenever there is DataReceived*/
class Class1 { /*just defining variables to automatically allocate a serial port, no need to follow*/
public SerialPort ZigbeePort; public string[] available_ports = SerialPort.GetPortNames(); RegistryKey myKey = Registry.LocalMachine.OpenSubKey("HARDWARE\\DEVICEMAP\\SERIALCOMM", false); public string[] valueNames; string name_of_module = "VCP0"; public int number_ports; public string COM_port_name; List<byte> HandlerReceived = new List<byte>(); public Form1 form; /*just opening a COM port, do not need to follow*/ public void init() { valueNames = myKey.GetValueNames(); /*Store the value names of the keys in a string array*/ number_ports = valueNames.Length; for (int i = 0; i < number_ports; i++) { if (valueNames[i].EndsWith(name_of_module)) { ZigbeePort = new SerialPort(available_ports[i], 9600, Parity.None, 8, StopBits.Two); if (!ZigbeePort.IsOpen) { ZigbeePort.Open(); } COM_port_name = available_ports[i]; } } ZigbeePort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); } /*Data Received handler*/ public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { byte[] TempRxData = new Byte[ZigbeePort.BytesToRead]; ZigbeePort.Read(TempRxData, 0, TempRxData.Length); for (int i = 0; i < TempRxData.Length; i++) { HandlerReceived.Add(Convert.ToByte(TempRxData[i])); } /*Just adding a name to the items list that the Listbox has*/ form.a.Add("Handler Item"); System.Console.WriteLine(HandlerReceived.Count); } } public partial class Form1 : Form { public BindingList <string> a = new BindingList <string>(); Class1 clas = new Class1(); public Form1() { InitializeComponent(); listBox1.DataSource = null; a.Add("1st Item"); a.Add("2nd Item"); listBox1.DataSource = a; clas.init(); clas.form = this; a.ListChanged += new ListChangedEventHandler(a_ListChanged); }
private void button1_Click(object sender, EventArgs e) { a.Add("Button item"); } void a_ListChanged(object sender, ListChangedEventArgs e) { /*cross threading occurs here*/ listBox1.Refresh(); } } }
- Upravený champion7891 16. dubna 2012 13:29
-
16. dubna 2012 13:43
"The Forms timer has an accuracy of +/- 50 mS."
That's an old wives tale. Somehow that got in the documentation in the Windows 95 time frame and it stuck. It's accuracy depends upon other activity on the thread. If there is no other activity on the thread, the CPU is a modern multicore and the OS is Win7, it can tick at 1ms intervals accurately.
Hmm, well how do you explain the following?
Here's the code. I created a default Windows Forms app, and changed the code as follows:
using System; using System.Diagnostics; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1: Form { public Form1() { InitializeComponent(); timer1 = new Timer(); timer1.Interval = 1; this.timer1.Tick += this.timer1_Tick; timer1.Enabled = true; sw.Restart(); } private void timer1_Tick(object sender, EventArgs e) { if (++count == 1000) { Trace.WriteLine(sw.Elapsed.TotalMilliseconds); sw.Restart(); count = 0; } } private Stopwatch sw = new Stopwatch(); private int count; private readonly Timer timer1; } }I then build and run the RELEASE version with DbgView running to capture the Trace.WriteLine() output. I run it on Window 7 x64 running on an i7 quad core with hyperthreading with nothing else taking CPU time (other than DbgView, which is only doing anything significant when it prints the trace output).
The results are as follows:
15598.6142
15588.6312
15606.1794If the timer was ticking about once per millisecond, the time for 1000 ticks should be around 1000, of course. Instead it's more than 15 times longer.
-
16. dubna 2012 14:05
"If the timer was ticking about once per millisecond, the time for 1000 ticks should be around 1000, of course. Instead it's more than 15 times longer"
You don't have a modern multicore CPU and the OS might not be Win7.
15 times 1ms isn't 50 ms. The timer can't tick more frequently than once per time slice. 10 ms on single core, 17 ms on dual core. My I7 time slice is less than 1 ms, so the timer can tick at 1 ms intervals
When the doc was written I believe the time slice of the OS at the time was 55 ms. Today every system seems to have its own time slice interval.- Upravený JohnWeinMicrosoft Community Contributor 16. dubna 2012 14:12
-
16. dubna 2012 14:29
You don't have a modern multicore CPU and the OS might not be Win7.
From my posting:
" I run it on Window 7 x64 running on an i7 quad core with hyperthreading with nothing else taking CPU time "
What happens if you try the same code on your i7?
Also note that behind the scenes, System.Windows.Forms.Timer uses the Windows API SetTimer().
The documentation for SetTimer is very precise about the minimum interval, uElapse:
(From http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906%28v=vs.85%29.aspx)
If uElapse is less than USER_TIMER_MINIMUM (0x0000000A), the timeout is set to USER_TIMER_MINIMUM. If uElapse is greater than USER_TIMER_MAXIMUM (0x7FFFFFFF), the timeout is set to USER_TIMER_MAXIMUM.
And note that USER_TIMER_MINIMUM is 10.
- Upravený Matthew Watson 16. dubna 2012 14:36
-
16. dubna 2012 14:54
"What happens if you try the same code on your I7?"
I get the same results. The last time I did any timing checks on my system, I thought the time slice was on the order of 1 ms. My point is though that the WF Timer doesn't have 50 ms accuracy. It has the same accuracy as the System.Timers.Timer. The accuracy is limited by the time slice of the system for XP and Vista. Not sure what determines the accuracy for Win7 or even what a time slice is on Win7.
I check the time slices using Sleep(1). It shows 1953 ms for 1000 iterations.
This is the statment from the Docs:
"The Windows Forms Timer component is single-threaded, and is limited to an accuracy of 55 milliseconds. If you require a multithreaded timer with greater accuracy, use the Timer class in the System.Timers namespace."
This statement has been there for at least a decade. Change the timer in your code to a System.Timers.Timer. You should get the same results as the Windows.Forms.Timer. The callback to the UI thread limits the timer.
I get the same times using your code with the Windows.Forms.Timer, the System.Timers.Timer and the System.Threading.Timer.
- Upravený JohnWeinMicrosoft Community Contributor 16. dubna 2012 15:36
-
16. dubna 2012 15:01
void a_ListChanged(object sender, ListChangedEventArgs e) { /*cross threading occurs here*/ listBox1.Refresh(); }
void a_ListChanged(object sender, ListChangedEventArgs e) { listBox1.Invoke(new MethodInvoker(doRefresh)); } void doRefresh() { listBox1.Refresh(); }this, although not tested should get rid of the cross threading exception... (Invoke calls the method on the same thread on which a control was made)
- Označen jako odpověď champion7891 17. dubna 2012 1:44
-
16. dubna 2012 17:01
-
16. dubna 2012 21:31Moderátor
This is the statment from the Docs:
"The Windows Forms Timer component is single-threaded, and is limited to an accuracy of 55 milliseconds. If you require a multithreaded timer with greater accuracy, use the Timer class in the System.Timers namespace."
This statement has been there for at least a decade.
The fact that it has been there for a decade is exactly why it cites such a high number. That was the performance of platforms at the time. Not every user is running the latest CPU or OS. I don't consider that figure to be a best case performance, but rather a worst case. On some older systems, that is the performance that you can expect. I feel that it is the correct figure to cite, worst case.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
-
16. dubna 2012 21:42
"On some older systems, that is the performance that you can expect. I feel that it is the correct figure to cite, worst case."
That system can't run the .NET framework.
I think you should consider only systems that are still being supported. Basically XP and later.
Try Matthew's code with any timer. What do you think about setting any timer to 1 ms?
-
16. dubna 2012 22:02Moderátor
"That system can't run the .NET framework."
Yes, they can. I have an HP that I bought in 2002 running VS2005 on it. That test posted above yields +/- 40 mS worst case performance. It was the first machine that I used to load install Visual Studio.
You can always put it into your "System Requirements" whatever OS, CPU type, and RAM size that you want. My point is simple. There are systems out there running the Framework with that type of performance.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
http://thesharpercoder.blogspot.com/
- Upravený Rudedog2MVP, Moderator 16. dubna 2012 22:02
-
16. dubna 2012 22:17
"That test posted above yields +/- 40 mS worst case performance."
Please explain that statement? Are you saying that Matthew"s test on that system gives an average 1ms interval with a variance of 40 ms?
A reasonable interpretation of the doc statement would be that I can time a 1 second interval with no better than a variance of 55 ms.
But, anything you can do to dissuade someone from trying to use a Windows timer to control and external process is positive.
-
16. dubna 2012 23:04Moderátor
If I set the interval to 0.1 second, the actual interval can vary by as much as 40 mS late corresponding to an interval of 140 mS. It will rarely go in the other direction.
Your "reasonable interpretation" is inaccurate. The docs are stating the worst case performance that you can expect.
"A reasonable interpretation of the doc statement would be that I can time a 1 second interval with no worse than a variance of 55 ms."
Saying it the other way means to me that the interval variance will be 55 mS or higher. The docs are stating that the interval error will be 55 mS or less.
[EDIT] It also means that interval settings less than that figure are not guaranteed to be reliable.
Mark the best replies as answers. "Fooling computers since 1971."
http://thesharpercoder.blogspot.com/
- Upravený Rudedog2MVP, Moderator 17. dubna 2012 22:53
-
16. dubna 2012 23:27Thanks a lot!
-
16. dubna 2012 23:41Moderátor
Thanks a lot!
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/4f60756c-d975-410c-a81a-f4821270059b
Check out that thread. I posted code for a form that compares all 3 timers at once.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
-
17. dubna 2012 1:44
Thanks a lot to everyone on this forum. With your pointers and tips, especially about using Invoke and Event handlers, I have been able to completely change my code, with UI refresh and Communications timers gone. I really appreciate all of your help and I believe I've really made progress thanks to you guys.
Here I would like to ask and clear a couple of questions:
1) Do event handlers run as threads?
2)Suppose that I have a timer (don't care which) running and the code that its executing hasn't finished completion, if an event interrupt or invoke occurs, will it run in parallel with the timer code, won't run till timer code is finished executing, or will the event/invoke block the timer code?
3) On a side note, I still have 1 system.timers.timer running. This is because I queue Unacknowledged transmissions which I would want to re transmit after an interval. Is there an elegant solution to avoid using a timer here :P.
4) Referring back to my original post (at the beginning) about the Data Acquisition class/module/timer, I would like to state a few things for your suggestions
A) I haven't implemented it yet. Its something that my group partner is doing independently and its code will be integrated with mine.
B) at some event and/or after every 30s, its used to acquire, for 1s, some data from mic in. The data to be acquired will probably be acquired at the KHz order frequency (haven't check that out yet with my partner).
C) there will be some heavy processing done on this data, some file I/Os as well
Is there any suggestion about the best method to do this? I mean, should my partner use threading timers for his acquisition etc. and simply raise an event whenever his processing is finished. I'd want it to sun in such a way that I would'nt have to change my code much?
- Upravený champion7891 17. dubna 2012 1:46
-
17. dubna 2012 18:14
Hi, apart from the above, I have a new issue. I tried to set up a threading timer:
public partial class GUI : Form { System.Threading.Timer timer; public GUI() { InitializeComponent(); timer = new System.Threading.Timer (new System.Threading.TimerCallback (OneSecondCallback) , null, 0, 1000); //Time is a label on the form Time.Text = DateTime.Now.ToString("hh:mm:ss tt"); } void OneSecondCallback(object state) { Time.Text = DateTime.Now.ToString("hh:mm:ss tt"); } }
However, my GUI crashes/closes as soon as this timer event occurs?
-
17. dubna 2012 19:39
"However, my GUI crashes/closes as soon as this timer event occurs?"
Fix the cross-thread calls. You were suppossed to learn that yesterday.
-
17. dubna 2012 22:51Moderátor
"However, my GUI crashes/closes as soon as this timer event occurs?"
Take a look at the code sample at the link that I posted. It uses InvokeRequired.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
-
18. dubna 2012 18:28
"However, my GUI crashes/closes as soon as this timer event occurs?"
Take a look at the code sample at the link that I posted. It uses InvokeRequired.
Rudy =8^D
Mark the best replies as answers. "Fooling computers since 1971."
Hey Rudy, I tried hooking up your code, but the form hangs, and well, I don't know why (though you did mention in your code as a comment that it will hang)?
System.Threading.Timer _Timer; delegate void UpdateControlCallback(string text); object threadLock1 = new object(); public form1() { InitializeComponent(); _Timer = new System.Threading.Timer(new System.Threading.TimerCallback(OneSecondCallback), null, 0, 1000); } void OneSecondCallback(object state) { string text = DateTime.Now.ToString("hh:mm:ss tt"); UpdateTime(text); } void UpdateTime(string text) { //please note that Time is a label on the form lock (threadLock1) { if (Time.InvokeRequired) { UpdateControlCallback action = new UpdateControlCallback(UpdateTime); this.Invoke(action, new object[] { text }); } else { Time.Text = text; } } }
- Upravený champion7891 18. dubna 2012 18:28
-
18. dubna 2012 19:41
You really should spend a little time trying to understand the Windows messaging system. Only one method can run on a thread at any time. Invoke sends a message to the message queue for a thread and waits until it is processed. It blocks the sending thread until the receiving thread dequeues the message and executes it. While the message is being processed, both threads are blocked. A big advantage to invoking the UI thread for synchronization is that no locks are necessary.
I don't think you can make the program you are trying to make without understanding Windows messagaging. If you throw code at the problem, you may get something to work, but it probably won't be reliable and you won't know how to troubleshoot to find problems.
Using a threading timer to do nothing but invoke the UI thread is simply coding for coding sakes. Use the Windows.Forms.Timer. It does exactly what you do, but with a lot less code.
- Upravený JohnWeinMicrosoft Community Contributor 18. dubna 2012 20:50