Reputation: 2614
In C# I am trying to create a Windows Service with two loops that will run simultaneously at set intervals. For example, LoopA will run every 30 seconds and LoopB every 5 seconds.
The tasks that will take place inside LoopA could take more than 30 secodns to complete. If this happens, LoopA will begin again immediately, where as if the task only takes 20 seconds, LoopA will not run again for 10 seconds.
I have already implemented LoopA. My problem now is implementing LoopB to run in parallel, behaving in the same way as LoopA except with a 5 second interval. Here is my LoopA code, which runs inside a Thread:
private Thread Worker;
private AutoResetEvent StopRequest;
private TimeSpan loop_a_freq;
private TimeSpan loob_b_freq;
public LoopManager(Thread _worker, AutoResetEvent _stopRequest)
{
// Threads
this.Worker = _worker;
this.StopRequest = _stopRequest;
RunLoopA();
}
private void RunLoopA()
{
DateTime start_current_loop = DateTime.Now;
DateTime next_loop = start_current_loop + loop_a_freq;
for (;;)
{
// Do processing here
new LoopAction();
DateTime now = DateTime.Now;
if (now > next_loop)
{
next_loop = now;
}
TimeSpan delay = next_loop - now;
Thread.Sleep(delay);
next_loop += loop_a_freq;
if (StopRequest.WaitOne(0))
{
return;
}
}
}
How do I go about implementing RunLoopB()
? Threads are the one aspect of C# I have never explored fully. Do I need to use Parallel.For()
?
Upvotes: 1
Views: 1558
Reputation: 4793
using System.Timers;
enum EventType {quit, task};
class LoopDaLoop {
Timer _30Seconds_publiser = new Timer(20000);
Timer _5Seconds_publisher = new Timer(5000);
Timer _terminator = new Timer(60000);
BlockingCollection<EventType> loopAEvents = new BlockingCollection<EventType>();
BlockingCollection<EventType> loopBEvents = new BlockingCollection<EventType>();
public LoopDaLoop() {
_30Seconds_publiser.Elapsed += _30Seconds_publiser_Elapsed;
_5Seconds_publisher.Elapsed += _5Seconds_publisher_Elapsed;
_terminator.Elapsed += _terminator_Elapsed;
_30Seconds_publiser.Start();
_5Seconds_publisher.Start();
_terminator.Start();
Task.Run(() => loopA());
Task.Run(() => loopB());
}
void _terminator_Elapsed(object sender, ElapsedEventArgs e) {
loopAEvents.Add(EventType.quit);
loopBEvents.Add(EventType.quit);
}
void _5Seconds_publisher_Elapsed(object sender, ElapsedEventArgs e) {
loopBEvents.Add(EventType.task);
}
void _30Seconds_publiser_Elapsed(object sender, ElapsedEventArgs e) {
loopAEvents.Add(EventType.task);
}
private void loopA() {
while (loopAEvents.Take() != EventType.quit) {
// decrypt wife's personal email
}
}
private void loopB() {
while (loopBEvents.Take() != EventType.quit) {
// navigate attack drones
}
}
}
Upvotes: 2
Reputation: 3289
Here is a little snippet you can put into linqpad and test with. This will prevent the timer from overlapping. Basically we execute the callback, stop the timer, process some work, reset the timer and start it up again. You would need a timer for each of your timed tasks.
To be clear, this will prevent your threads from needlessly queueing up as you are only creating a new thread to process work once the other one is finished. Having 2 timers will allow you to run 2 different processes at different intervals creating their own threads. Again, allowing only one instance of each process to happen per timer.
Basic Process
Basic Code
private System.Timers.Timer _timer;
private int _delaySeconds = 5;
void Main()
{
// timer prevents threads from overlapping modify with care
_timer = new System.Timers.Timer();
_timer.Interval = _delaySeconds*1000;
_timer.AutoReset = true; // important to prevent overlap
_timer.Elapsed += OnProcess;
_timer.Start();
}
private void OnProcess(object sender, System.Timers.ElapsedEventArgs args)
{
// timer prevents from thread overlapping modify with care
_timer.Stop();
// do work
Debug.WriteLine("Processing on thread. [{0}]", Thread.CurrentThread.ManagedThreadId).Dump("this");
// setting the interval resets the timer
_timer.Interval = _delaySeconds*1000;
_timer.Start();
}
Troubleshooting Performance
Also, I found this article yesterday which may be helpful for you on diagnosing your threading performance.
http://msdn.microsoft.com/en-us/library/ee329530.aspx
Upvotes: 2
Reputation: 10708
This seems to be almost entirely ready to go, but in order to get the other thread running, you'll want to kick off the first thread in parallel, same for the second, and the wait them both. This might be easier using Task
s instead of Threads
, but here it is using Thread
s
public LoopManager(Thread _worker, AutoResetEvent _stopRequest)
{
// Threads
this.Worker = _worker;
this.StopRequest = _stopRequest;
var threadA = new Thread(RunLoopA);
var threadB = new Thread(RunLoopB);
// Start the loops
threadA.Start();
threadB.Start();
// Join the threads to avoid the program exiting before they're done
threadA.Join();
threadB.Join();
}
private void RunLoopB() {...} // As RunLoopA, but using the loop_b_freq variable
Now if you want to be able to ensure that each loop kicks off without waiting for the previous process to finish, you're starting to look at an implementation better served by the System.Timers.Timer
class. Be aware there is also a System.Threading.Timer
that you do not want to use in this situation because it lacks the event patterns.
Upvotes: 1