Execute scheduled Task only once - c#

I was trying to Code some simple scheduled Task, which should be executed every full minute (aka when seconds are at 0) but somehow it got messed up. Instead of only doing its job once, it does it over and over as long as the seconds are at 0.
I tried to prevent that by using a bool indicator, but that didnt work.
Hier is my Code example:
static void Main()
{
bool now = true;
while (true)
{
if (DateTime.Now.Second == 0 && now == true)
{
Console.WriteLine("now is: " + DateTime.Now);
now = false;
}
else
{
now = true;
}
}
}
I would prefer to not use sleeps or delays and would like to schedule it by actual time.
Is there an easy way to solve this?

Keep track of your current time and your next run time by changing your code to something like
static void Main(string[] args)
{
var now = DateTime.Now;
var nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0).AddMinutes(1);
while (true)
{
var currentTime = DateTime.Now;
if (currentTime >= nextRunTime)
{
Console.WriteLine(currentTime);
nextRunTime = nextRunTime.AddMinutes(1);
}
}
}

Related

Delay in while loop and its precision

I am writing C# code to make data acquire system from FPGA with USB communication and not that familiar with C#.
The system received data continuously at regular intervals through USB.
Data is continuously received only when DOPPLER_NUM = 1, and while (DOPPLER_NUM == 1) is that process.
And there are two problems in operation.
When I operate code without Delay(1) in while loop, the program is completely stopped and none of the buttons in the program works.
I used Delay function to solve the problem, and it works.
But, the delay I want is 1ms and it actually varies from 1-15ms when I measured it with Stopwatch function.
public void Delay(int MS)
{
DateTime ThisMoment = DateTime.Now;
TimeSpan Duration = new TimeSpan(0, 0, 0, 0, MS);
DateTime AfterWards = DateTime.Now.Add(Duration);
while (AfterWards >= ThisMoment)
{
System.Windows.Forms.Application.DoEvents();
ThisMoment = DateTime.Now;
}
return;
}
int DOPPLER_NUM = 0;
private void Doppler_Start_Click(object sender, EventArgs e)
{
int transmit_mode = 1;
if (DOPPLER_NUM == 0)
{
DOPPLER_NUM = 1;
transmit_mode = 1;
}
else
{
DOPPLER_NUM = 0;
transmit_mode = 0;
cnt4GS = 0;
}
CyBulkEndPoint Inednpt1;
Inednpt1 = MyDevice.EndPointOf(0x86) as CyBulkEndPoint;
int bytes1 = Convert.ToInt32(256);
int bytes2 = bytes1 * 2;
bool bXferCompleted = false;
bool IsPkt = false;
byte[] buffer4GS = new byte[400 * 256];
byte[] buffer1 = new byte[bytes2];
byte[] Data_buf = new byte[bytes1];
while (DOPPLER_NUM == 1)
{
Stopwatch clk1 = new Stopwatch();
clk1.Start();
Delay(1);
clk1.Stop();
opertime.Text = (clk1.ElapsedTicks * 100 / 1000).ToString() + " us";
if (MyDevice != null)
{
if (Inednpt1 != null)
{
bXferCompleted = Inednpt1.XferData(ref buffer1, ref bytes2, IsPkt); // Data receiving from USB
Data_buf = Doppler_Processing(buffer1, bytes2);
if (cnt4GS >= 0 && cnt4GS <= 399)
{
Buffer.BlockCopy(Data_buf, 0, buffer4GS, cnt4GS * 256, 256);
cnt4GS++;
}
else if (cnt4GS >= 400)
{
Buffer.BlockCopy(buffer4GS, 256, buffer4GS, 0, 102144);
Buffer.BlockCopy(Data_buf, 0, buffer4GS, 102144, 256);
}
Grayscale(buffer4GS);
}
}
else if (MyDevice == null)
{
MessageBox.Show("ERROR. NODEVICE.", "Error Message");
break;
}
}
Your Delay method gives the UI thread to handle events, by calling System.Windows.Forms.Application.DoEvents();
If you have an intensive operation bound to your UI thread (which explains the behaviour) you'll end up with a blocked UI. The usage of System.Windows.Forms.Application.DoEvents(); can resolve this, but it would be better to just execute your DOPPLER_NUM loop in another thread - not bothering the UI thread with it and keeping your program responsive.
Alternatively, you can just call System.Windows.Forms.Application.DoEvents(); from your loop itself and it would work just as good, maybe increasing performance a bit.
Also:
Alternatives like Task.Delay and Thread.Sleep will not have a better accuracy as about 5ms. This is by design - because measuring the exact time will cost CPU power, same as the stopwatch does.

Launch a program every 12 hours

I want to launch a method in a program every 12 hours.
What do I have to do ?
Do I have to use a Timer to doing this ?
I have this code :
aTimer = new System.Timers.Timer(1000); //One second, (use less to add precision, use more to consume less processor time
int lastHour = DateTime.Now.Hour;
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Start();
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(lastHour < DateTime.Now.Hour || (lastHour == 23 && DateTime.Now.Hour == 0))
{
lastHour = DateTime.Now.Hour;
YourImportantMethod(); // Call The method with your important staff..
}
}
Can I adapt it to launch my program every 12 hours ?
A simple solution with async/await:
private static async void RepeatedAction()
{
TimeSpan delay = TimeSpan.FromHours(12);
while (true)
{
await Task.Delay(delay);
YourImportantMethod();
}
}
Use System.Threading.Timer
var start = TimeSpan.Zero;
var period = TimeSpan.FromHours(12);
var timer = new System.Threading.Timer((e) =>
{
YourImportantMethod();
}, null, start, period);
You can use Cron Jobs for this situation
Here is url check and implement. In corn job you can set when your program run

Timer to exact time by seconds

I'm trying to run an infinite loop in parallel with the other code, that is executed once a specific time acheived by SECOND.
In the below code I'm trying to touch the exact midnight time, that is: 00 hh: 00 mm: 00 sec
using System; // for Date/Time
using System.Threading.Tasks; // for Parallel
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
() =>
{
Console.WriteLine("Begin first task...");
}, // close first Action
async () =>
{
Console.WriteLine("Begin second task...");
var midNight = "00:00:00";
while (true)
{
TimeSpan duration = DateTime.Parse(midNight).Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds",
duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.Days >= 1)
await Task.Delay(8640000);
else if(duration.Hours >= 1)
await Task.Delay(360000);
else if(duration.Minutes >= 1)
await Task.Delay(60000);
else
await Task.Delay(1000);
if(duration == TimeSpan.Zero) {
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
} // close second Action `the async task`
) // end of Parallel.Invoke
} // End of Main
} // End of Program
I was able to the await statement work correctly to reach the required point, but the lock the condition if(duration == TimeSpan.Zero) never become true
First of all your program can't work as you showed because your TimeSpan duration = DateTime.Parse(midNight).Subtract(DateTime.Now); never will be positive. Second you main function will return almost immediately. Anyway you can try my solution for your problem:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
() =>{Console.WriteLine("Begin first task...");},
async () =>
{
Console.WriteLine("Begin second task...");
DateTime startDate = DateTime.Today;
while (true)
{
TimeSpan duration = DateTime.Now.Subtract(startDate);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds",
duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
int delay = (int)(DateTime.Today.AddDays(1.0).Subtract(DateTime.Now).TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
if(duration.Days >= 1)
{
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
startDate = DateTime.Today;
}
}
}
);
}
}
This will not provide you super precision as on normal PC you can't get it (you could use IRQ to get better accuracy but solution like that is far more complex).
Also as prof of concept link to 10s version.
At time version:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
async () =>
{
Console.WriteLine("Begin second task...");
TimeSpan eventTime = new TimeSpan(0,18,16,53,123); //set when run event (ex. 18:16:53.123)
DateTime endDate = DateTime.Today.Add(eventTime);
if(endDate<DateTime.Now) endDate = endDate.AddDays(1.0);
while (true)
{
TimeSpan duration = endDate.Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds", duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.TotalMilliseconds <= 0.0)
{
Console.WriteLine("It is time... {0}", DateTime.Now);
endDate = endDate.AddDays(1.0);
continue;
}
int delay = (int)(duration.TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
}
}
);
Thread.Sleep(6000);
}
}
I was able to do it by changing the condition from:
if(duration == TimeSpan.Zero)
to:
if(duration.Days == 0 && duration.Hours == 0 && duration.Minutes == 0 && duration.Seconds == 0)
and to avoid the double occurrence of the event, i added another await level, so the new one became like:
if(duration.Days >= 1)
await Task.Delay(8640000);
else if(duration.Hours >= 1)
await Task.Delay(360000);
else if(duration.Minutes >= 1)
await Task.Delay(60000);
else if(duration.Seconds >= 1)
await Task.Delay(1000);
else
await Task.Delay(500);
I tried adding the if(duration.Milliseconds >= 1) await(1) but did not work, my output became as shown below:
The problem is that in your case, the duration is never zero, it goes from plus some milliseconds to minus some milliseconds.
What I would do: If duration is less than one second, wait for duration and then just assume it's the right time. In code:
if (duration.Days >= 1)
await Task.Delay(8640000);
else if (duration.Hours >= 1)
await Task.Delay(360000);
else if (duration.Minutes >= 1)
await Task.Delay(60000);
else if (duration.Seconds >= 1)
await Task.Delay(1000);
else
{
// defensive check in case duration is already negative
// this should not normally happen, but is still possible
if (duration > TimeSpan.Zero)
await Task.Delay(duration);
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
}
This won't give you millisecond accuracy, but it should be the right second, under normal circumstances.

How to check thread is sleeping in x second c#

I write application need check if time to checkLogin() sleep over > 30 seconds.
Then, it will break this while loop and continues the program.
My code like this:
while(!Account.checkLogin())
{
Thread.Sleep(1000);
}
How to check like:
while(!Account.checkLogin())
{
Thread.Sleep(1000);
if(Thread.Sleep like 30000)
continues;
}
If I understood the question correctly, you could sum up the iterations and and use them in the termination condition as follows.
int MAX_ITERATIONS = 30;
int NumOfIterations = 0;
while(!Account.checkLogin() && NumOfIterations < MAX_ITERATIONS)
{
Thread.Sleep(1000);
NumOfIterations++;
}
You can just sleep for 30 seconds:
Thread.Sleep(30000);
However that's holding up the thread and stops you doing anything inbetween. I prefer to use a TimeSpan, for example:
DateTime started = DateTime.UtcNow;
while (!Account.checkLogin())
{
TimeSpan ts = DateTime.UtcNow - started;
if (ts.TotalSeconds >= 30)
break;
Thread.Sleep(1000);
}

Thread program, 1st and last loop never has a ThreadedState other than 'Running'

I have a programming that is looping x times (10), and using a specified number of threads (2). I'm using a thread array:
Thread[] myThreadArray = new Thread[2];
My loop counter, I believe, starts the first 2 threads just fine, but when it gets to loop 3, which goes back to thread 0 (zero-based), it hangs. The weird thing is, if I throw a MessageBox.Show() in their to check the ThreadState (which shows thread 0 is still running), it will continue on through 9 of the 10 loops. But if no MessageBox.Show() is there, it hangs when starting the 3rd loop.
I'm using .NET 3.5 Framework (I noticed that .NET 4.0 utilizes something called continuations...)
Here's some code examples:
Thread[] threads = new Thread[2];
int threadCounter = 0;
for (int counter = 0; counter < 10; counter++)
{
if (chkUseThreading.Checked)
{
TestRunResult runResult = new TestRunResult(counter + 1);
TestInfo tInfo = new TestInfo(conn, comm, runResult);
if (threads[threadCounter] != null)
{
// If this is here, then it will continue looping....otherwise, it hangs on the 3rd loop
MessageBox.Show(threads[threadCounter].ThreadState.ToString());
while (threads[threadCounter].IsAlive || threads[threadCounter].ThreadState == ThreadState.Running)
Thread.Sleep(1);
threads[threadCounter] = null;
}
// ExecuteTest is a non-static method
threads[threadCounter] = new Thread(new ThreadStart(delegate { ExecuteTest(tInfo); }));
threads[threadCounter].Name = "PerformanceTest" + (counter + 1);
try
{
threads[threadCounter].Start();
if ((threadCounter + 1) == threadCount)
threadCounter = 0;
else
threadCounter++;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Application.DoEvents();
}
}
while (true)
{
int threadsFinished = 0;
for (int counter = 0; counter < threadCount; counter++)
{
if (!threads[counter].IsAlive || threads[counter].ThreadState == ThreadState.Stopped)
threadsFinished++;
}
if (threadsFinished == threadCount)
break;
else
Thread.Sleep(1);
}
Obviously the problem is something about how I'm checking to see if thread #1 or #2 is done. The IsAlive always says true, and the ThreadState always has "running" for threads loops 1 and 10.
Where am I going wrong with this?
Update, here's the ExecuteTask() method:
private void ExecuteTest(object tInfo)
{
TestInfo testInfo = tInfo as TestInfo;
Exception error = null;
DateTime endTime;
TimeSpan duration;
DateTime startTime = DateTime.Now;
try
{
if (testInfo.Connection.State != ConnectionState.Open)
{
testInfo.Connection.ConnectionString = connString;
testInfo.Connection.Open();
}
testInfo.Command.ExecuteScalar();
}
catch (Exception ex)
{
error = ex;
failedCounter++;
//if (chkCancelOnError.Checked)
// break;
}
finally
{
endTime = DateTime.Now;
duration = endTime - startTime;
RunTimes.Add(duration);
testInfo.Result.StartTime = startTime;
testInfo.Result.EndTime = endTime;
testInfo.Result.Duration = duration;
testInfo.Result.Error = error;
TestResults.Add(testInfo.Result);
// This part must be threadsafe...
if (lvResults.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(ExecuteTest);
this.Invoke(d, new object[] { tInfo });
}
else
{
lvResults.Items.Add(testInfo.Result.ConvertToListViewItem());
#region Update Results - This wouldn't work in it's own method in the threaded version
const string msPrefix = "ms";
// ShortestRun
TimeSpan shortest = GetShortestRun(RunTimes);
tbShortestRun.Text = shortest.TotalMilliseconds + msPrefix;
// AverageRun
TimeSpan average = GetAverageRun(RunTimes);
tbAverageRun.Text = average.TotalMilliseconds + msPrefix;
// MeanRun
TimeSpan mean = GetMeanRun(RunTimes);
tbMeanRun.Text = mean.TotalMilliseconds + msPrefix;
// LongestRun
TimeSpan longest = GetLongestRun(RunTimes);
tbLongestRun.Text = longest.TotalMilliseconds + msPrefix;
// ErrorCount
int errorCount = GetErrorCount(TestResults);
tbErrorCount.Text = errorCount.ToString();
#endregion
}
testInfo.Command.Dispose();
Application.DoEvents();
}
}
Can you post a snippet of run ()? Doesn't Thread.currentThread().notifyAll() help? May be each thread is waiting for other thread to do something resulting in a deadlock?

Categories