Why does my main form take 20+ seconds to become visible? - c#

I must be missing something obvious, but I simply do not understand why my main form in my Windows Forms Application is taking 20 seconds to show up. My program is an attempt to take a TPL code example I found in a console application example and make in work in a windows form/gui. I KNOW the queuing of tasks will take 20 seconds to complete, but does that section of code occur so fast that the form has not had time to finish initialization? I tried putting a delay right after "InitializeComponent();" in hopes that it would give the form time to come up; and also tried to put just a messagebox after, but still get the same delay after my inserted delay. There is no form_load method, so there is nothing to check there.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Time the test(s)
Stopwatch stoppwatch = new Stopwatch();
stoppwatch.Start();
Console.SetOut(new ControlWriter(tb1)); // just redirects console.writeline to the form's textbox "tb1"
// #################################### job queue ########################################
var q = new TPLDataflowMultipleHandlers(); //
var numbers = Enumerable.Range(1, 10);
foreach (var num in numbers)
{
F1TimeDelay(2);
q.Enqueue(num.ToString());
}
// Stop the timer and return the elapsed number of milliseconds.
stoppwatch.Stop();
Console.WriteLine("XXXXXXXXXX <STATUS> Elapsed time = {0} minutes. XXXXXXXXXX", (int)stoppwatch.Elapsed.TotalMinutes);
}
As an aside, when the form does finally show up, the text box is full of the messages I was expecting to see from the launched threads (info like thread id, etc).
F1TimeDelay(2) is a 2 second delay, while the queued jobs are just 10 second long tasks to demonstrate the 10 tasks running in parallel. The numbers sent to the queue end up being job numbers for the 10 tasks.

Because somewhere between the Constructor and FormShown Event, you are calling code that takes 20+ seconds to complete.
While I can see nothing in the constructor, that is litearlly just the start of the loading process: https://learn.microsoft.com/en-us/dotnet/framework/winforms/order-of-events-in-windows-forms
Generally the earliest moment you should retreive any data or do anything else, is in the Shown Event. And even then, a long running operation such as this should be done with some form of Multitasking/Asynchronous operation. You have to figure out what it is, but my guess is for a Disk or Network/Database Access.
If you want to do measurements with a hope of correctnes, you need to start the StopWatch in the Constructor, and only stop/show the result in Shown. And even then your Shown Event might be the 1st one called with the hard/long work comming later, so it might miss whatever causes the issues. Your Stopwatch also does not include the Designer created Elements. The Designer code is executed with InitializeComponents(). Of course with delay on such an order of Magnitude, it should be feasible to just output DateTime.Now regulary.

The form will show sometime after the constructor is done. If you put the long running task queuing code into the constructor, the form wont show until this long running code is done.
Instead add a button to the form and create a click handler for it. put the long running code there. Then the form will show up and you can click the button. But then the form will freeze, because of the task queuing, i guess.

Related

C# timer start at exact full second

Is there a way to run the Timer so that it starts at exact full second?
stateTimer = new Timer(someCallback, null, 0, 1000);
This one will start right away, repeating each second, but the problem is it will start exactly when I run the program which may result in 13:14:15.230 start.
I would like 13:14:15.000 start. Something like:
stateTimer = new Timer(someCallback, null, DateTime.Now.Date, 1000);
Is that possible?
EDIT:
After doing the console log:
Console.WriteLine($"Time: {DateTime.Now.ToString("HH:mm:ss.fff")}");
I've noticed that 1 second interval actually gets incremented by more than one second (about 1,02 each iteration) so after 50 iterations one second is skipped. I have solved my problem by making timer run each 800ms instead. Not ideal solution, but it works, and second never gets skipped (and I have no problem in triggering the same second twice).
stateTimer = new Timer(someCallback, null, 0, 800);
No that is not possible. That would require you to exactly know when the CPU thinks it is a good idea to start to execute your timer code. Even if you would Thread.Sleep for the remaining time, it would still not mean the code is executed at the very millisecond you want to.
Instead, if you just want to do this for formatting, you can use a custom date/time format to do that.
I had to do something similar in a program that displayed the time and displayed the number of minutes and seconds until the user could do something.
The original code used a 1000 ms timer. This had the problems described by the original poster. I created a thread. The thread had a loop:
private ManualResetEvent myThreadRequestExit = new ManualResetEvent(false);
while (!myThreadRequestExit.WaitOne(1000 - DateTime.UtcNow.Millisecond))
{
// Do the one-second work here
}
The loop will exit and the thread will terminate when MyThreadRequestExit is set.
Although it may fire a few milliseconds after the start of the second it is close enough that the user perceives the timer as ticking when it should and it does not lose seconds as long as the work can be done in less than a second.
Just add this line before you start your timer. Sweet and simple :)
Thread.Sleep(1000 - DateTime.Now.Millisecond);

C# Thread.Sleep(1000) takes much more than 1000ms on some pc

I write a c# program to count down 5 seconds. What I do is:
new Task(() =>
{
try
{
this.Invoke((Action)delegate()
{
label1.Text = "5"; // 4, 3, 2..etc
});
}
Thread.Sleep(1000);
}
catch
{
// form could be disposed
break;
}
}
}).Start();
This works on my PC, however, when I copied the program to a window tablet, the Thread.Sleep(1000) gives more than 1 second. In other words, it takes more than 5 seconds (in fact more than 10 seconds) to update the label from 5,4,3,2,1. Alternatively, it takes too long to update label1.Text = "5", etc? It does not make sense to me. I wonder what is wrong?
Sleep will wait at least that long before activating the thread again, but it can always be longer than that. After the one second time has passed the thread becomes eligible to execute by the CPU scheduler, and the scheduler is able to run it whenever it wants to. If it's particularly busy, and/or is using a scheduling algorithm that doesn't focus on quickly allowing newly active threads to run, it could be some time.
Servy's answer is correct. For more details, please read the documentation:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298.aspx
which states:
Note that a ready thread is not guaranteed to run immediately. Consequently, the thread may not run until some time after the sleep interval elapses. For more information, see Scheduling Priorities.
The priority documentation is here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms685100.aspx
More generally though: you are doing something deeply wrong. Do not ever use Sleep like this. If you want to wait some amount of time then use a timer or use a Delay task. Never sleep a thread like this outside of test code. The right way to write your code is probably something like
for (int countdown = 5; countdown > 0; countdown -= 1)
{
label1.Text = countdown.ToString();
await Task.Delay(1000);
}
Or, make a class that has a timer and a counter, start the timer to tick a few times a second, compare the current time to the time when you last updated the label, and if more than a second has elapsed, update the label.

Which way is better, and how to pass parameters to windows.forms.timer

What I want to accomplish it the following thing:
I have a lot of "checks(if/else if etc)" inside a timer, that his interval is 1000 ms,
there is a text file that getting updated and the timer read it every 1000 ms and check for some specific changes,
under 1 of those conditions if it is true the timer, i need to wait 10 sec and then read another text file and then continue with the rest of the timer code.
but in the mean time the timer keep running under those 10 sec and preform the checks every 1sec for all the other conditions and this 1 also.
what i thought to do it
if the conditions i wanted it true i will start a new timer with 10sec interval and it will continue with the code of that specific part.
but what i have hard time to accomplish is how to pass parameters into that timer
such as
newTimer.Start(int "parameter", string "parameter b", list<string> parameters c")
etc etc
or if you got any other idea i will be glad to hear.
To pass parameters, you can always use Tuple.
newTimer.Start(Tuple.Create(param1, param2, param3));
You might not need to have two timer if you do the logic correctly.
Timer *run every second*
Check file
If file has flag Then save in variable the current date + 10 seconds
If current date > saved date Then Check the other file
You need to consider that a System.Windows.Forms.Timer will run on the GUI thread (the thread that run the containing form's message loop / pump), as it uses window messages (WM_TIMER) that are processed by the GUI thread. Because of that, any code that runs under any System.Windows.Forms.Timer in your form will execute synchronously. So, if your start a new System.Windows.Forms.Timer which blocks for 10 seconds, all your other timers will be blocked as well (since the message loop is blocked).
Consider using a System.Threading.Timer or System.Timers.Timer, as they run the timer callback on a different thread. This way, your code will run pretty much as you'd want - every one second the method will be running, regardless of weather the previous call completed or is still blocking (waiting 10 seconds).

Acceptable use of Thread.Sleep()

I'm working on a console application which will be scheduled and run at set intervals, say every 30 minutes. Its only purpose is to query a Web Service to update a batch of database rows.
The Web Service API reccommends calling once every 30 seconds, and timeout after a set interval. The following pseudocode is given as an example:
listId := updateList(<list of terms>)
LOOP
WHILE NOT isUpdatingComplete(listId)
END LOOP
statuses := getStatuses(“LIST_ID = {listId}”)
I have coded this roughly in C# as:
int callCount = 0;
while( callCount < 5 && !client.isUpdateComplete(listId, out messages) )
{
listId = client.updateList(options, terms, out messages);
callCount++;
Thread.Sleep(30000);
}
// Get resulting status...
Is it OK in this situation to use Thread.Sleep()? I'm aware it is not generally good practice but from reading reasons not to use it this seems like acceptable usage.
Thanks.
Thread.Sleep ensures the current thread doesn't return until at least the specified milliseconds have passed. There are plenty of places it's appropriate to do that, and your example seems fine, assuming it's running on a background thread.
Some example places you don't want to use it - on the UI thread or where you need to do exact timing.
Generally speaking, Thread.Sleep is like any other tool: perfectly OK to use, except when it's terribly misused. I disagree with the "not generally good practice" part, which is the result of people abusing Thread.Sleep when they should be doing something else (i.e. blocking on a synchronization object).
In your case the program is single-threaded, it has no UI (i.e. the thread has no message loop) and you do not want to synchronize with external events. Therefore Thread.Sleep is just fine.
The general objection against Sleep() is that it wastes a Thread.
In your case there is only 1 Thread (maybe 2) so that is not really a problem.
So I think it looks fine (but I would sleep 29 seconds to cut some slack).
It's fine, except that you cannot interrupt it once it goes into sleep, without aborting the thread (which is not recommended).
That's why a ManualResetEvent might be a better idea, since it can be signalled ("awaken") from a different thread.
you could stick with the Thread.Sleep method. But it would be more elegant to schedule it to run every 30 minutes - so you don't have to take care of the waiting inside your application.
Thread.Sleep isn't the best for executing periodic logic. Thread.Sleep(n) means your thread will relinquish control for n milliseconds. There is no guarantee that it will regain control after n milliseconds, it depends on the CPU load.
If you are locking the thread for 30 mins case you should schedule a windows task every 30 mins, so the program executes and then ends. That way you are not locking a thread for so long.
For shorter times, like 30 secs / 1 min, System.Thread.Sleep() is perfectly fine. For more than 5 mins i would use a windows task. (Im spanish i think on the english version are called like that, im talking about the tasks you schedule from the control panel ;-) )

Timer is starting late, hence shows the time which is a second late then actual time

I have a timer. But it starts a second late.I mean, i am clocking a time according to the timer. But the time in the clock, which updates through timer, is one second less then the actual time elapsed. The timer starts off a second late. How to set my timer to start at right time to show actual time? this is the code inside tick event:
if (currentState == play)
{
m_StatusLabel.Text = String.Format("Playing {0} ", format(timeCounter));
timeCounter++;
}
Here timeCounter is updating with each second.
Standard System.Windows.Forms timers give no guarantees about 'metronome quality'. For that, you would need either a Systems.Threading.Timer or a System.Timer.
Ref: Comparing the Timer Classes in the .NET Framework Class Library
There are no timers available that will gaurantee true-time accuracy, not even System.Threading.Timer can do that. For example, when you ask Threading.Timer to fire in 30ms, it might actually take 40ms or 200ms. Or if you ask for 1 second, it might fire in 1.01 seconds. In won't take long before your time is inaccurate.
The reason for this is that the timer makes the callback thread schedulable, but it still takes time for the thread scheduler to actually call the thread. Various operations the system is performing can delay that callback.
A Windows timer makes only one guarantee: it won't fire before the timeout interval elapses. Specifically, a thread will never receive a timer event while there are messages in its message queue.
Consequently you can't use timers to implement a clock. If you want to update a status message to show how long something has been playing, then you could try this: record the start time, and when your timer ticks get the current time, subtract the start time, and dislay the difference. Your status message won't be updated exactly every second, but when it is updated it will be correct.
Show a number 1 greater:
if (currentState == play)
m_StatusLabel.Text = String.Format("Playing {0} ",
format(++timeCounter) );
NOTE
Please consider the reason of those who suggested displaying the elapsed time as current time - start time. That is the way this is usually done. It is more accurate; a timer can be irregular on a busy system. It is still possible to update the displayed value every second. Pseudo code here for now(). This requires acquiring current time and performing a time difference.
if (currentState == play)
m_StatusLabel.Text = String.Format("Playing {0} ",
format( (now() - start)/1000 );
See Also:
1. DateTime.Subtraction
2. DateTime.Now

Categories