Question

I have a console application that runs at :00 of every hour. This console application copies files at :15 and :30 of the very same hour.

This was my initial code, where I use a WHILE loop to check the current minute. I would like to replace the WHILE loop with a System.Threading.Timer.

Using Threading.Timer and without using a loop, how can I launch Thread0 at 15 minutes after the start of the console app and Thread1 at 30 minutes? I do not want to use 3rd-party, open-source solutions.

CancellationTokenSource cts0 = new CancellationTokenSource();
CancellationTokenSource cts1 = new CancellationTokenSource();

Thread Thread0, Thread1;

DateTime TaskRunDateTime = DateTime.Now;
DateTime RightNow = DateTime.Now;

while (!thread0Running || !thread1Running)
{
    if (RightNow.Minute == 15)
    {
        thread0Running = true;
        Class myClass0 = new Class();
        Thread0 = new Thread(() => myClass0.CopyFiles(15, cts0.Token));
        Thread0.Start();
    }
    else if (RightNow.Minute == 30)
    {
        thread1Running = true;
        Class myClass1 = new Class();
        Thread1 = new Thread(() => myClass1.CopyFiles(30, cts1.Token));
        Thread1.Start();
    }
    RightNow = DateTime.Now;
}

for (; ; )
{
    fileCount = Directory.GetFiles(destPath, FileDate + "*.xml").Length;
    If (fileCount == 20)
    {  
        // All 20 files have been copied because the two threads have finished
        RunExternalReportGeneratorEXE();
        break;
    }
    else if (RightNow >= TaskRunDateTime.AddHours(2))
    {
        // Task took over 2 hours to complete. 
        // Cancel Thread0, Thread1 and run 3rd-party executable.
        cts0.Cancel();
        cts1.Cancel();
        RunExternalReportGeneratorEXE();
        break;
    }
Was it helpful?

Solution 2

Create two ManualResetEvent objects that you can wait on. Then create two timers:

ManualResetEvent Copy1Done = new ManualResetEvent(false);
ManualResetEvent Copy2Done = new ManualResetEvent(false);

Timer t1 = new Timer((s) =>
    {
        Class myClass0 = new Class();
        myClass0.CopyFiles(15, cts0.Token);
        Copy1Done.Set();
    }, null, TimeSpan.FromMinutes(15), TimeSpan.FromMilliseconds(-1));
Timer t1 = new Timer((s) =>
    {
        Class myClass1 = new Class();
        myClass0.CopyFiles(30, cts1.Token);
        Copy2Done.Set();
    }, null, TimeSpan.FromMinutes(30), TimeSpan.FromMilliseconds(-1));

Those are one-shot timers; they'll fire once, and then won't fire again.

Now, you want to wait up to two hours for the copies to complete. That's where the ManualResetEvent objects come in. Create an array of the events:

WaitHandle[] handles = new WaitHandle[] {Copy1Done, Copy2Done};

// wait for both events to be signaled, or for two hours
if (!WaitHandle.WaitAll(handles, TimeSpan.FromHours(2)))
{
    // took too long. Cancel the copies.
    cts0.Cancel();
    cts1.Cancel();
    // you might want to wait here for the threads to exit.
    // otherwise you might have a problem with a locked file.
}
// and run the program
RunExternalReportGeneratorEXE();

OTHER TIPS

At the point you application starts you can calculate how long until X:15 and X:30 will fall. You could then use the Timer's constructor to schedule the start time of the timer callback and the frequency.

I don't want to write the whole code here for you but to give you an idea what you can do with thread timer:

void CreateTimer()
{
    // Create an event to signal the timeout count threshold in the 
    // timer callback.
    AutoResetEvent autoEvent     = new AutoResetEvent(false);
    // Create an inferred delegate that invokes methods for the timer.
    TimerCallback tcb = CheckStatus;
    // Create a timer that signals the delegate to invoke  
    // CheckStatus after 15 minutes. 
    // thereafter.
    Console.WriteLine("{0} Creating timer.\n", DateTime.Now.ToString("h:mm:ss.fff"));
    System.Threading.Timer Timer stateTimer = new Timer(tcb, autoEvent, 1000 * 60 *15, 0);
    //Wait for 15 minutes
    autoEvent.WaitOne(1000 * 60 *15, false);
    stateTimer  = new Timer(tcb, null, 1000 * 60 *30, 0);
}

// This method is called by the timer delegate. 
public void CheckStatus(Object stateInfo)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), stateInfo);
}

public void DoWork(Object stateInfo)
{
    AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
    autoEvent.Set();
    //Change your worktype here.
    CancellationTokenSource cts0 = new CancellationTokenSource();
    Class myClass1 = new Class();
    myClass1.CopyFiles(30, cts0.Token);

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top