I have a while loop that waits for a local setting value to no longer be null. In the event that something is borked and the value remains null, is there some sort of best practice for how you should break out of the loop? Right now I just have it counting up to 100 and if it's looped 100 times to break the loop:
int i = 0;
while (ApplicationData.Current.LocalSettings.Values["MediaInfoSaved"] == null)
{
await Task.Delay(15);
i++;
if(i >= 100)
{
break;
}
}
The loop is waiting for a process in a full trust helper to finish and return it's result. The process can take a while to complete sometimes (0.1-1 second).
Put the value (represented as 100 in your code) in a config file so it's easily changed if needed. If issues pop up later you can adjust it as needed.
If the process is expected to take up to a second, then wait for just a second. No need to loop and increment a counter:
private async Task<object> GetLocalSettingAsync()
{
const string SettingName = "MediaInfoSaved";
// Try to get the value immediately:
var setting = ApplicationData.Current.LocalSettings.Values[SettingName];
if (setting != null)
return setting;
// Wait for one second only.
await Task.Delay(TimeSpan.FromSeconds(1));
// Return either a value or null.
return ApplicationData.Current.LocalSettings.Values[SettingName];
}
If you want to exit as fast as possible but wait for up to a second, then spin in a loop and poll the property:
private async Task<object> GetLocalSettingAsync()
{
const string SettingName = "MediaInfoSaved";
DateTime start = DateTime.UtcNow;
object setting;
do
{
setting = ApplicationData.Current.LocalSettings.Values[SettingName];
if (setting != null)
break;
//optionally wait here:
await Task.Delay(15);
} while (DateTime.UtcNow.Subtract(start).TotalSeconds < 1);
return setting;
}
I am afraid it doesn't get any better unless the object that you are monitoring raises some kind of event or callback when there is data available.
It is very common practice to implement a timeout, where you wait a specified amount of time (if you have an idea how long the process should be taking) before breaking out of the loop. This is basically what you have implemented. If you think it shouldn't take more than 1 second to complete, make sure it breaks the loop after 1.5-2 seconds. There may be more effective ways to implement this, like using the actual time within the system.
Related
For a side project at work I'm trying to have a piece of code that is run every 24 hours at a certain time. My boss asked me to use an infinite loop instead of C#'s timer class so that's the main constraint I'm working with. My problem is that the code will work for the first 24 hours (i.e. it will run the code on the day that I set it to) but then it won't update after that. I'm not being thrown any exceptions or errors so I'm assuming it's just a problem with my logic.
Here's the gist of the code I have now.
int i = 0;
while (true)
{
DateTime currentdate = DateTime.Now;
String time = currentdate.ToString("HH:mm");
if ((time == "23:50" || time == "23:51") && i == 0)
{
HistoricalAverageCollection HAC = new HistoricalAverageCollection();
HAC.ExecHAC();
HistoricalAverageError HAE = new HistoricalAverageError();
HAE.ExecHAE();
FourWeekAverageCollection FWAC = new FourWeekAverageCollection();
FWAC.ExecFWAC();
FourWeekAverageError FWAE = new FourWeekAverageError();
FWAE.ExecFWAE();
DomainsReturningZeroTwentyFourHours DRZ =
new DomainsReturningZeroTwentyFourHours();
DRZ.ExecDomainsReturningZero();
context.SaveChanges();
//Program should update every 24 horus
i = 1;
Console.Write("Updated The Historical Averages In The Data Base at...");
Console.Write(DateTime.Now);
Console.WriteLine("i is -> {0}", i);
Console.Read();
}
else if (time == "06:00" && i == 1)
{
ReportEmail Report = new ReportEmail();
Report.CreateAndSendReport();
i = 0;
Console.Write("counter reset. I is now -> {0} /n Email Sent",i);
Console.Read();
}
}
The code is set up to call a bunch of tsql stored procedures at 11:50 Pm and then send out an email report based on that data at 6 in the morning. However, it will only run once and I find myself waking up in the morning a day or two later and seeing that no emails are being sent.
Any help would be appreciated :)
I would second the many comments suggesting other, better suited methods of doing this, but I believe your problem is the lines with:
Console.Read();
From the documentation:
The Read method blocks its return while you type input characters; it
terminates when you press the Enter key.
So it will block waiting for an entry that will never come.
Keep a time variable that indicates the "Next" datetime to run.
In your loop just check if the current time of after that and run your code.. then reset the variable to the next daytime i.e. Now + 24 hours.
as another answer indicates the issue is with the line:
Console.Read();
which needs to be removed
If you really want to do this all by hand without using timers or existing scheduler facilities, I'd recommend being a little more rigorous and building a simple task scheduler class yourself. The parts you'll need:
A class to store each task, which includes the code to execute for the task and the schedule for when each task should run.
A list of such tasks
A method to compute when the next deadline is from your list of tasks, so you know how long to sleep for.
A SemaphoreSlim to sleep on (instead of Thread.Sleep())
Use a SemaphoreSlim because it acts as a Thread.Sleep() by passing it a wait time if the semaphore is never released; but also because you can manually release it if your scheduler determines that a new task has been added and it should wake up to re-evaluate the next deadline.
I'd recommend storing your deadlines in UTC, and doing the majority of the time computation work using UTC time, this way there's no confusion about time zone changes or DST.
You also should consider not just sleeping for the entire time until the next deadline, just in case there are NTP updates to the PC's system time. Consider sleeping for a maximum of 1 hour at a time.
Some highlights to get you started:
public void Run()
{
this.running = true;
do
{
DateTime nextDeadlineUtc;
ScheduledTask nextTask;
bool deadlineExpired;
nextDeadlineUtc = ComputeNextDeadline( out nextTask );
deadlineExpired = WaitForDeadline( nextDeadlineUtc );
if( deadlineExpired )
{
// We hit the deadline. Execute the task and move on.
nextTask.Execute();
}
else
{
// We were woken up before the deadline expired. That means either we're shutting
// down, or we need to recompute our next deadline because the schedule changed.
// To deal with this, just do nothing. We'll loop back around and either find out
// we're being asked to stop, or we'll recompute the next deadline.
}
}
while( this.running );
}
/// <summary>
/// Sleeps until the deadline has expired.
/// </summary>
/// <param name="nextDeadlineUtc">The next deadline, in UTC</param>
/// <returns>
/// True if the deadline has elapsed; false if the scheduler should re-examine its next deadline.
/// </returns>
private bool WaitForDeadline( DateTime nextDeadlineUtc )
{
TimeSpan wait;
bool incompleteDeadline;
bool acquired;
wait = ComputeSleepTime( nextDeadlineUtc, out incompleteDeadline );
acquired = this.waiter.Wait( wait );
if( acquired || incompleteDeadline )
{
// Either:
// - We were manually woken up early by someone releasing the semaphore.
// - The timeout expired, but that's because we didn't wait for the complete time.
//
// Either way, the deadline didn't expire.
return false;
}
else
{
// The deadline occurred.
return true;
}
}
private TimeSpan ComputeSleepTime( DateTime nextDeadlineUtc, out bool incompleteDeadline )
{
TimeSpan totalRemaining = nextDeadlineUtc - DateTime.UtcNow;
if( totalRemaining.Ticks < 0 )
{
// Were already out of time.
incompleteDeadline = false;
return TimeSpan.FromTicks( 0 );
}
else if( totalRemaining.TotalHours <= 1.01 )
{
// Just sleep the whole of the remainder.
incompleteDeadline = false;
return totalRemaining;
}
else
{
// More than one hour to sleep. Sleep for at most one hour, but tell the sleeper that
// there's still more time left.
incompleteDeadline = true;
return TimeSpan.FromHours( 1.0 );
}
}
Is there a way in c# to call a method so that if the method takes to long to complete, the method will be canceled and it will return to the calling method? I think I can do this with threading but what if threading is not needed?
For reference, the method I may need to kill/stop/abort is calling the CorelDraw 15 API. This opens an instance of CorelDraw and I have received non-repeatable errors in this method. Meaning, I can process the same image twice and one time it will freeze or error and the other it will not.
The current solution to the issue I am using is to have a second application that does Process.Start(firstAppExecutablePath) and then checks a variable in a text file and if the variable doesn't change after 10 minutes, .Kill(); is called on the instance of the process. I would prefer to avoid this solution if possible as it seems clunky and prone to issues. Since it runs .Kill(); it is being very messy in how things close but generally does not cause an issue.
Not built-in, no, since interrupting arbitrary code cannot be done safely (what if it's in the middle of calling a C library function (that doesn't support exceptions) which has just taken a global lock and needs to release it?).
But you can write such support yourself. I wouldn't add threads to the mix unless absolutely necessary, since they come with an entire new dimension of potential problems.
Example:
void Caller()
{
int result;
if (TryDoSomething(out result, 100)) {
System.Console.WriteLine("Result: {0}", result);
}
}
bool TryDoSomething(out int result, int timeoutMillis)
{
var sw = Stopwatch.StartNew();
result = 0x12345678;
for (int i = 0; i != 100000000; ++i) {
if (sw.ElapsedMilliseconds > timeoutMillis)
return false;
result += i / (result % 43) + (i % 19);
}
return true;
}
Threading is absolutely needed unless you are ok with checking the timeout from within the function - which probably you arn't. So here is a minimalistic approach with threads:
private static bool ExecuteWithTimeout(TimeSpan timeout, Action action)
{
Thread x = new Thread(() => { action(); });
x.Start();
if (!x.Join(timeout))
{
x.Abort(); //Or Interrupt instead, if you use e.g. Thread.Sleep in your method
return false;
}
return true;
}
I have a counter, which counts the currently processed large reports
private int processedLargeReports;
and I'm generating and starting five threads, where each thread accesses this method:
public bool GenerateReport(EstimatedReportSize reportSize)
{
var currentDateTime = DateTimeFactory.Instance.DateTimeNow;
bool allowLargeReports = (this.processedLargeReports < Settings.Default.LargeReportLimit);
var reportOrderNextInQueue = this.ReportOrderLogic.GetNextReportOrderAndLock(
currentDateTime.AddHours(
this.timeoutValueInHoursBeforeReleaseLock),
reportSize,
CorrelationIdForPickingReport,
allowLargeReports);
if (reportOrderNextInQueue.IsProcessing)
{
Interlocked.Increment(ref this.processedLargeReports);
}
var currentReport = this.GetReportToBeWorked(reportOrderNextInQueue);
var works = this.WorkTheReport(reportOrderNextInQueue, currentReport, currentDateTime);
if (reportOrderNextInQueue.IsProcessing)
{
Interlocked.Decrement(ref this.processedLargeReports);
}
return works;
}
the "reportOrderNextInQueue" variable gets a reportorder from the database and checks whether the report order is either "Normal" or "Large" (this is achieved by defining the bool IsProcessing property of reportOrderNextInQueue variable). In case of a large report, the system then Interlock Increments the processedLargeReport int and processes the large report. Once the large report is processed, the system Interlock Decrements the value.
The whole idea is that I'll only allow a single report to be processed at a time, so once a thread is processing a large report, the other threads should not be able to access a large report in the database. The bool allowLargeReport variable checks whether the processedLargeReports int and is above the limit or not.
I'm curious whether this is the proper implementation, since I cannot test it before Monday. I'm not sure whether I have to use the InterLocked class or just define the processedLargeReports variable as a volatile member.
Say you have 5 threads starting to run code above, and LargeReportLimit is 1. They will all read processedLargeReports as 0, allowLargeReports will be true for them, and they will start processing 5 items simultaneously, despite your limit is 1. So I don't really see how this code achieves you goal, if I understand it correctly.
To expand it a bit: you read processedLargeReports and then act on it (use it to check if you should allow report to be processed). You act like this variable cannot be changed between read and act, but that is not true. Any number of threads can do anything with processedLargeReports in between you read and act on variable, because you have no locking. Interlocked in this case will only ensure that processedLargeReports will always get to 0 after all threads finished processing all tasks, but that is all.
If you need to limit concurrent access to some resourse - just use appropriate tool for this: Semaphore or SemaphoreSlim classes. Create semaphore which allows LargeReportLimit threads in. Before processing report, Wait on your semaphore. This will block if number of concrurrent threads processing report is reached. When processing is done, release your semaphore to allow waiting threads to get in. No need to use Interlocked class here.
volatile does not provide thread safety. As usual with multithreading you need some synchronization - it could be based on Interlocked, lock or any other synchronization primitive and depends on your needs. You have chosen Interlocked - fine, but you have a race condition. You read the processedLargeReports field outside of any synchronization block and making a decision based on that value. But it could immediately change after you read it, so the whole logic will not work. The correct way would be to always do Interlocked.Increment and base your logic on the returned value. Something like this:
First, let use better name for the field
private int processingLargeReports;
and then
public bool GenerateReport(EstimatedReportSize reportSize)
{
var currentDateTime = DateTimeFactory.Instance.DateTimeNow;
bool allowLargeReports =
(Interlocked.Increment(ref this.processingLargeReports) <= Settings.Default.LargeReportLimit);
if (!allowLargeReports)
Interlocked.Decrement(ref this.processingLargeReports);
var reportOrderNextInQueue = this.ReportOrderLogic.GetNextReportOrderAndLock(
currentDateTime.AddHours(
this.timeoutValueInHoursBeforeReleaseLock),
reportSize,
CorrelationIdForPickingReport,
allowLargeReports);
if (allowLargeReports && !reportOrderNextInQueue.IsProcessing)
Interlocked.Decrement(ref this.processingLargeReports);
var currentReport = this.GetReportToBeWorked(reportOrderNextInQueue);
var works = this.WorkTheReport(reportOrderNextInQueue, currentReport, currentDateTime);
if (allowLargeReports && reportOrderNextInQueue.IsProcessing)
Interlocked.Decrement(ref this.processingLargeReports);
return works;
}
Note that this also contains race conditions, but holds your LargeReportLimit constraint.
EDIT: Now when I'm thinking, since your processing is based on both Allow and Is Large Report, Interlocked is not a good choice, better use Monitor based approach like:
private int processingLargeReports;
private object processingLargeReportsLock = new object();
private void AcquireProcessingLargeReportsLock(ref bool lockTaken)
{
Monitor.Enter(this.processingLargeReportsLock, ref lockTaken);
}
private void ReleaseProcessingLargeReportsLock(ref bool lockTaken)
{
if (!lockTaken) return;
Monitor.Exit(this.processingLargeReportsLock);
lockTaken = false;
}
public bool GenerateReport(EstimatedReportSize reportSize)
{
bool lockTaken = false;
try
{
this.AcquireProcessingLargeReportsLock(ref lockTaken);
bool allowLargeReports = (this.processingLargeReports < Settings.Default.LargeReportLimit);
if (!allowLargeReports)
{
this.ReleaseProcessingLargeReportsLock(ref lockTaken);
}
var currentDateTime = DateTimeFactory.Instance.DateTimeNow;
var reportOrderNextInQueue = this.ReportOrderLogic.GetNextReportOrderAndLock(
currentDateTime.AddHours(
this.timeoutValueInHoursBeforeReleaseLock),
reportSize,
CorrelationIdForPickingReport,
allowLargeReports);
if (reportOrderNextInQueue.IsProcessing)
{
this.processingLargeReports++;
this.ReleaseProcessingLargeReportsLock(ref lockTaken);
}
var currentReport = this.GetReportToBeWorked(reportOrderNextInQueue);
var works = this.WorkTheReport(reportOrderNextInQueue, currentReport, currentDateTime);
if (reportOrderNextInQueue.IsProcessing)
{
this.AcquireProcessingLargeReportsLock(ref lockTaken);
this.processingLargeReports--;
}
return works;
}
finally
{
this.ReleaseProcessingLargeReportsLock(ref lockTaken);
}
}
I would like to use this solution to call Console.ReadLine() with a timeout:
delegate string ReadLineDelegate();
string ReadLine(int timeoutms)
{
string resultstr = null;
ReadLineDelegate d = Console.ReadLine;
IAsyncResult result = d.BeginInvoke(null, null);
result.AsyncWaitHandle.WaitOne(timeoutms);//timeout e.g. 15000 for 15 secs
if (result.IsCompleted)
{
resultstr = d.EndInvoke(result);
Console.WriteLine("Read: " + resultstr);
}
else
{
Console.WriteLine("Timed out!");
// Bug? resource leak? No d.EndInvoke(), which blocks until Console.ReadLine() returns
}
result.AsyncWaitHandle.Close();
return resultstr;
}
but commenters warned:
every ReadLine you call sits there waiting for input.
If you call it 100 times, it creates 100 threads
which don't all go away until you hit Enter 100 times!
...especially because I want to call this repeatedly in a forever-loop.
I understand that every BeginInvoke() needs a EndInvoke() but I don't want a blocking EndInvoke call in the else branch. Somehow we need to abort the running Console.ReadLine() call rather than let it run to completion, because it may never complete.
So all this (complex) code helped me to get Console.ReadLine to return at a timeout, but does not end the Console.ReadLine to quit or otherwise go away.
How can we make this to work correctly, without running into resource leaks?
NB: I added the AsyncWaitHandle.Close() as advised by MS Calling Sync calls asynchronously
After reading a lot of comments on several similar questions, as mentioned, I come to believe there is no real solution here. The Microsoft way with Begin/EndInvoke is
rather complex, and:
not adequate
A more straightforward method is to run the synchronous call in another thread, use a timing method to keep track of the timeout, and use Thread.Abort() to get rid of the timed-out synchronous call.
Caveat:
The synchronous call may or may not support to be aborted. For example, Console.ReadLine() will be aborted OK, but if you restart the thread, no data will be read from the Console anymore.
The accepted solution on the original question on top of my posting above uses a second thread, and a timing method. However, it does not kill the sychronous call but keeps it running because it is needed for subsequent async calls, which is a fine hack.
The code for using a second thread is actually straighforward:
public class MySyncProc
{
/// <summary>
/// Value returned from the process after completion
/// </summary>
public string Result = null;
...other shared data...
public MySyncProc() { }
public void Run()
{
Result = LengthyProcess(...);
return;
}
}
public string Run(int TimeoutMs)
{
MySyncProc SyncP = new MySyncProc() { arg1 = ..., etc };
//
Thread T = new Thread(SyncP.Run);
T.Start();
//
DateTime StopTime = DateTime.Now.AddMilliseconds(TimeoutMs);
while (DateTime.Now < StopTime && SyncP.Result == null)
{
Thread.Sleep(200);
}
if (T.IsAlive)
{
T.Abort();
Console.WriteLine("Aborted thread for: {0}", Name);
}
return SyncP.Result;
}
If you don't like the polling, use the slightly more complex AutoResetEvent as in the mentioned accepted solution.
I have a piece of code that searches several third party APIs. I have the searches split into 2 groups based on the search criteria. I start both searches because each search is quite timely, but if the first group of searches results in an match I don't want to wait around for the second search group to finish. So basically what I have is:
Dictionary<string, string> result = null;
NameSearchDelegate nameDel = new NameSearchDelegate(SearchByName);
IAsyncResult nameTag = nameDel.BeginInvoke(name, null, null);
if(!string.IsNullOrWhiteSpace(telNum))
{
result = SearchByTelNum(telNum);//Will return null if a match is not found
}
if(null == result)
{
result = nameDel.EndInvoke(nameTag);
}
//End the delegate to prevent memory leak
//else
//{
// nameDel.EndInvoke(nameTag)
//}
return result;
So I want to start the SearchByName before I call SearchByTelNum in case it does not find a match, however if it does find a match I don't want to have to wait for SearchByName to finish before returning the match. Is there any way to simply end or cancel that delegate if I no longer need its result?
I was able to solve my problem using System.ComponentModel.BackgroundWorker. I wasn't necessarily using it in the way it is intended to be used but it was able to do what I needed. So basically what my new code looks like is:
Dictionary<string, string> telResult = null,
nameResult = null;
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (obj, e) => nameResult = SearchByName(name, bw);
bw.RunWorkerAsync();
if(!string.IsNullOrWhiteSpace(telNum))
telResult = SearchByTelNum(telNum);//Will return null if a match is not found
if(telResult != null)
{
bw.CancelAsync;
return telResult;
}
bool hasTimedOut = false;
int i = timeOutCount;
while (bw.IsBusy && !hasTimedOut)
{
System.Threading.Thread.Sleep(500);
if (0 == --i) hasTimedOut = true;
}
return nameResult;
And to make sure there are no bugs, I had to make sure that SearchByName periodically checks if bw.CancellationPending equals true, and ends the method in that case. CancelAsync does not end the worker thread, it simply alerts the worker thread that caller thread has canceled it.
Also I could have simply used
while(bw.IsBusy) System.Threading.Thread.Sleep(500)
to wait for the method to complete, but if something bad happens in SearchByName you could end up waiting forever in an infinite loop. This way I can set an amount of time before the method is considered to have timed out and the caller thread just goes on with life. In this case, since I check bw.IsBusy every .5 seconds, the timeout length is equal to timeOutCount / 2 seconds.
Ok I think I have thoroughly answered my own question.
I have handled this by defining an abortable parameter object
public class AbortableParameter<T>
{
public T Parameter { get; private set }
public bool ShouldAbort { get; set; }
public AbortableParameter(T parameter)
{
Parameter = parameter;
ShouldAbort = false;
}
}
Just create an instance of this class with any parameters you want to pass to the delegate and keep a reference to it; setting it to true if the delegate should exit. The delegate then needs to periodically check ShouldAbort and exit gracefully when it becomes true.
This is the downside, the delegate must check periodically or it won't matter if it should abort or not.
It is also possible to have the ShouldAbort property's set method kill the delegate when it is set to true, but this is not a graceful exit and should be avoided in most cases -- but it does have the benefit of not requiring the delegate polling.