How would you synchronise multiple threads to be at a certain place in their code at a particular time?
I am not looking for WaitAll, await etc. As in the example code, the threads do not return, only one thread is created per worker.
I have made this monster...
It works for simple and slow cases, but there is a race condition: when a fast thread locks _sync before the synchroniser. As a result sometimes that thread will execute more than once per cycle and break any assumptions of what is ready for use by other threads.
static readonly Stopwatch timer = new Stopwatch();
static readonly object _locker1 = new object();
static readonly object _locker2 = new object();
...
static readonly object _sync = new object();
static void Main()
{
Task.Run(Synchroniser);
Task.Run(DoWork1);
Task.Run(DoWork2);
...
}
static void Synchroniser()
{
while (true)
{
lock (_sync)
{
timer.Restart();
while (timer.ElapseMilliseconds < 16) ;
lock (_locker1) ;
lock (_locker2) ;
...
}
}
}
static void DoWork1()
{
while (true)
{
lock (_locker1)
{
//all worker threads continue from here at the same time
...
}
lock (_sync) ;
}
}
...
It's hard to tell what kind of behavior you're after, but I think this is what you're trying to achieve. Run it and see how it behaves...
The code makes use of the ManualResetEvent class and the WaitAll function:
class Program
{
static readonly ManualResetEvent startWorkers = new ManualResetEvent(false); // workers initially blocked
static readonly ManualResetEvent worker1 = new ManualResetEvent(false);
static readonly ManualResetEvent worker2 = new ManualResetEvent(false);
static readonly Random R = new Random();
static void Main()
{
Task.Run(new Action(Synchroniser));
Task.Run(new Action(DoWork1));
Task.Run(new Action(DoWork2));
Console.ReadLine(); // keep program from closing
}
static void Synchroniser()
{
ManualResetEvent[] workers = new ManualResetEvent[] { worker1, worker2 };
while (true)
{
Console.WriteLine("Pausing...");
Thread.Sleep(5000); // long pause so we can see what is happening
Console.WriteLine("Signalling workers.");
startWorkers.Set(); // allow workers to run
startWorkers.Reset(); // workers can only run ONCE until we set again
Console.WriteLine("Waiting for all workers to be done...");
WaitHandle.WaitAll(workers); // wait for all the workers to be done
Console.WriteLine("All workers are done.");
worker1.Reset();
worker2.Reset();
}
}
static void DoWork1()
{
while (true)
{
Console.WriteLine("Worker1 waiting.");
startWorkers.WaitOne(); // wait here until signalled
// ... do something in here ...
Console.WriteLine("Worker1 processing...");
Thread.Sleep(R.Next(3000, 10000)); // random amount of work
Console.WriteLine("Worker1 done.");
worker1.Set(); // let Synchroniser know we are done
}
}
static void DoWork2()
{
while (true)
{
Console.WriteLine("Worker2 waiting.");
startWorkers.WaitOne(); // wait here until signalled
// ... do something in here ...
Console.WriteLine("Worker2 processing...");
Thread.Sleep(R.Next(3000, 10000)); // random amount of work
Console.WriteLine("Worker2 done.");
worker2.Set(); // let Synchroniser know we are done
}
}
}
Sample output:
Worker1 waiting.
Pausing...
Worker2 waiting.
Signalling workers.
Waiting for all workers to be done...
Worker2 processing...
Worker1 processing...
Worker1 done.
Worker1 waiting.
Worker2 done.
Worker2 waiting.
All workers are done.
Pausing...
Signalling workers.
Waiting for all workers to be done...
Worker2 processing...
Worker1 processing...
Worker1 done.
Worker1 waiting.
Worker2 done.
Worker2 waiting.
All workers are done.
Pausing...
If somehow the worker thread finishes before startWorkers.Reset();
I think it's unlikely to happen, but here's a two gate system that should prevent that from happening. After signalling that the thread is done, it will sit and wait until all threads have completed before being allowed to continue:
class Program
{
static readonly ManualResetEvent startWorkers = new ManualResetEvent(false); // workers initially blocked
static readonly ManualResetEvent releaseWorkers = new ManualResetEvent(false); // workers initially blocked
static readonly ManualResetEvent worker1 = new ManualResetEvent(false);
static readonly ManualResetEvent worker2 = new ManualResetEvent(false);
static readonly Random R = new Random();
static void Main()
{
Task.Run(new Action(Synchroniser));
Task.Run(new Action(DoWork1));
Task.Run(new Action(DoWork2));
Console.ReadLine(); // keep program from closing
}
static void Synchroniser()
{
ManualResetEvent[] workers = new ManualResetEvent[] { worker1, worker2 };
while (true)
{
Console.WriteLine("Pausing...");
Thread.Sleep(5000); // long pause so we can see what is happening
Console.WriteLine("Signalling workers.");
startWorkers.Set(); // allow workers to run, automatically reset
startWorkers.Reset();
Console.WriteLine("Waiting for all workers to be done...");
WaitHandle.WaitAll(workers); // wait for all the workers to be done
Console.WriteLine("All workers are done.");
Console.WriteLine("Resetting workers...");
// Reset all workers
foreach(ManualResetEvent mre in workers)
{
mre.Reset();
}
// release the workers to wait at the top of their loops
Console.WriteLine("Releasing workers...");
releaseWorkers.Set();
releaseWorkers.Reset();
}
}
static void DoWork1()
{
while (true)
{
Console.WriteLine("Worker1 waiting.");
startWorkers.WaitOne(); // wait here until signalled
// ... do something in here ...
Console.WriteLine("Worker1 processing...");
Thread.Sleep(R.Next(3000, 10000)); // random amount of work
Console.WriteLine("Worker1 done.");
worker1.Set(); // let Synchroniser know we are done
Console.WriteLine("Worker1 waiting for release...");
releaseWorkers.WaitOne(); // wait for all clear
}
}
static void DoWork2()
{
while (true)
{
Console.WriteLine("Worker2 waiting.");
startWorkers.WaitOne(); // wait here until signalled
// ... do something in here ...
Console.WriteLine("Worker2 processing...");
Thread.Sleep(R.Next(3000, 10000)); // random amount of work
Console.WriteLine("Worker2 done.");
worker2.Set(); // let Synchroniser know we are done
Console.WriteLine("Worker2 waiting for release...");
releaseWorkers.WaitOne(); // wait for all clear
}
}
}
You should have a look at the wait() function and such for the Task class.
It provides a way to continue execution of the current thread when a Task or a given array of tasks finishes execution.
For reference: https://learn.microsoft.com/en-gb/dotnet/api/system.threading.tasks.task.wait?view=netcore-3.1
So for example:
static void Main()
{
Task t1 = Task.Run(() => DoStuff_1("Task"));
Task t2 = Task.Run(() => DoStuff_2("Task"));
Task.WaitAll({t1, t2}); // Blocks the current thread till the given tasks finish execution
}
Related
I'm currently trying to implement a real-time multithreading software in C#. I need 3 threads. Every thread execution has to be finished before a deadline (500µs / 100µs / 50µs). The threads must run parallel during the whole runtime (until the user shuts down the program).
Is there a mecanism that can guarantee that the thread execution will not pass the deadline?
Here is my code :
static void Main(string[] args)
{
Thread thread1 = new Thread(FirstThread);
Thread thread2 = new Thread(SecondThread);
Thread thread3 = new Thread(ThirdThread);
thread1.start();
thread2.start();
thread3.start();
}
static void FirstThread()
{
while(true)
{
SleepMicroSec(500);
}
}
static void SecondThread()
{
while(true)
{
SleepMicroSec(100);
}
}
static void ThirdThread()
{
while(true)
{
SleepMicroSec(50);
}
}
private static void SleepMicroSec(long microSec)
{
var sw = Stopwatch.StartNew();
while (sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)) < microSec)
{
}
}
I expect the scheduler to be able to perform the context switching if the Task deadline is reached.
Thanks in advance for your answers !
Here is a method that invokes repeatedly an action in a background thread, aborting and restarting the thread every time the deadline is passed. It also accepts a CancellationToken to allow for premature cancellation of the procedure (before the end of the program).
private static void RepeatInBackgroundThread(Action action, int timeout,
CancellationToken cancellationToken)
{
var timer = new System.Timers.Timer(timeout);
timer.AutoReset = false; // to raise the Elapsed event only once
var thread = new Thread(() =>
{
while (true)
{
if (cancellationToken.IsCancellationRequested) return;
timer.Start();
action();
timer.Stop();
}
});
timer.Elapsed += (sender, e) =>
{
thread.Abort();
thread.Join(); // Wait for the thread to die
if (cancellationToken.IsCancellationRequested) return;
RepeatInBackgroundThread(action, timeout, cancellationToken);
};
thread.IsBackground = true;
thread.Start();
}
Usage example:
var random = new ThreadLocal<Random>(() => new Random());
var cts = new CancellationTokenSource();
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 1000)), 500, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 200)), 100, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 100)), 50, cts.Token);
//cts.CancelAfter(10000);
It should be noted that aborting threads is not a good practice in general.
Consider the following:
//base stuff
private readonly ConcurrentQueue<message> queue = new ConcurrentQueue<message>();
private readonly MyCacheData _cache = new MyCacheData ();
//setuo
timer = new Timer { Interval = 60_000, AutoReset = true };
timer.Elapsed += OnTimedEvent;
httpClient.Timeout = new TimeSpan(0, 0, 60); // 60 seconds too
//
// each 60 seconds
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (cache 30 minutes old)
{
//Fire and Forget GetWebDataAsync()
// and continue executing next stuff
// if I await it will wait 60 seconds worst case
// until going to the queue and by this time another
// timed even fires
}
// this always should execute each 60 seconds
if (queue isnt empty)
{
process queue
}
}
// heavy cache update each 10-30 minutes
private async Task GetWebDataAsync()
{
if (Semaphore.WaitAsync(1000))
{
try
{
//fetch WebData update cache
//populate Queue if needed
}
catch (Exception)
{
}
finally
{
release Semaphore
}
}
}
Colored: https://ghostbin.com/paste/6edov
Because I cheat and use the cheap ConcurrentQueue solution I don't really care much about what happens during GetWebDataAsync(), I just want to fire it and do its job, while I instantly go to process queue because it always must be done each 60 seconds or timer resolution.
How do I correctly do that, avoid much overhead or unnecessary thread spawning?
EDIT: got an answer for my case elsewhere
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
async void DoGetWebData() => await GetWebDataAsync()
if (condition)
{
DoGetWebData(); // Fire&Forget and continue, exceptions handled inside
}
//no (a)waiting for the GetWebDataAsync(), we already here
if (queue isnt empty)
{
//process queue
}
}
private async Task GetWebDataAsync()
{
if (Semaphore.WaitAsync(1000))
{
try
{
//fetch WebData update cache
//populate Queue if needed
}
catch (Exception)
{
//log stuff
}
finally
{
///always release lock
}
}
}
Task.Run(...);
ThreadPool.QueueUserItem(...);
Anything wrong with these?...
How about something like that:
ManualResetEvent mre = new ManualResetEvent(false);
void Foo()
{
new Thread(() =>
{
while (mre.WaitOne())
{
/*process queue item*/
if (/*queue is empty*/)
{
mre.Reset();
}
}
}) { IsBackground = true }.Start();
}
void AddItem()
{
/*queue add item*/
mre.Set();
}
Call an async method from another async method without await statement
The WinForm application has 20 threads running in the background, each one waits on the mutex. When signaled, it does "a job" as in Thread.Sleep for around 100ms and releases it. Then waits 1 second, and does the job again.
private Mutex locker;
private void NewThread()
{
Thread thread = new Thread(ThreadLoopMutex);
thread.Priority = ThreadPriority.BelowNormal;
thread.Name = threadCounter++.ToString("D2");
thread.Start();
}
private void ThreadLoopMutex()
{
PrintLog("was created");
while (true)
{
PrintLog("Lock1");
locker.WaitOne();
Thread.Sleep(100);
PrintLog("UnLock1");
locker.ReleaseMutex();
Thread.Sleep(1000);
PrintLog("Lock2");
locker.WaitOne();
Thread.Sleep(100);
PrintLog("UnLock2");
locker.ReleaseMutex();
}
}
public Form1()
{
InitializeComponent();
locker = new Mutex();
Thread.CurrentThread.Name = "GUI";
Thread.CurrentThread.Priority = ThreadPriority.Highest;
for (int i = 0; i < 20; i++)
{
NewThread();
}
}
When the GUI Thread tries to wait on the same mutex, it never signals. It will wait on the Mutex for a long time while the other threads are playing with it smoothly.
When I set the 20 threads' job time to 30ms instead of 100ms, then the GUI Thread enters the mutex freely.
private void button1_Click(object sender, EventArgs e)
{
PrintLog("Lock");
locker.WaitOne();
Thread.Sleep(500);
PrintLog("UnLock");
locker.ReleaseMutex();
}
Why is that?
I need a method to run accurately every 5 minutes. I can't use Timer because I noticed it will slowly become out of sync (i.e. it will eventually run at 00:01, 00:06, 00:11, 00:16, and so on).
Although it needs to be accurate, I don't need it to be too precise. Every 5 minutes +/- 1 second will be okay, just as long as after days of running, it will still tick accurately on the 5 minute marks.
What I have thought of so far is creating a Timer with an Interval of 1 second that constantly checks DateTime.Now to see if the next 5 minute mark is passed. I am wondering if there is a more elegant solution or something in the C# libraries that I have missed.
Edit: I have the following template now, which is working to my requirements.
public class ThreadTest
{
private Thread thread;
private long nextExecutionTime;
private long interval;
public void StartThread(long intervalInMillis)
{
interval = intervalInMillis * TimeSpan.TicksPerMillisecond;
nextExecutionTime = DateTime.Now.Ticks;
thread = new Thread(Run);
thread.Start();
}
private void Run()
{
while (true)
{
if (DateTime.Now.Ticks >= nextExecutionTime)
{
nextExecutionTime += interval;
// do stuff
}
}
}
}
if you are not happy with Timer?
then you can try to make your thread sleep for 5 mintues, instead of using Timer
have a look this, hope it helps
using System;
using System.Threading;
public class Worker
{
// This method will be called when the thread is started.
public void DoWork()
{
while (!_shouldStop)
{
Task.Factory.Start(() =>
{
// do you task async
})
Thread.Sleep(300000);
}
}
public void DoWork2()
{
var watch = new Stopwatch();
while (!_shouldStop)
{
watch.Start();
Task.Factory.Start(() =>
{
// do you task async
})
while(watch.Elapsed.ElapsedMilliseconds < 300000);
watch.Stop();
watch.Reset();
}
}
public void RequestStop()
{
_shouldStop = true;
}
private volatile bool _shouldStop;
}
public class WorkerThreadExample
{
static void Main()
{
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start();
// Loop until worker thread activates.
while (!workerThread.IsAlive);
while (true)
{
//do something to make it break
}
// Request that the worker thread stop itself:
workerObject.RequestStop();
workerThread.Join();
}
}
or you can try this:
I have written a DirectSoundWrapper but I just can access the interfaces through MTA Threads.
So I created a Thread that is working in background and executes actions in a queue.
I've done something like this:
private void MTAQueue()
{
lock (queueLockObj)
{
do
{
if (marshalThreadItems.Count > 0)
{
MarshalThreadItem item;
item = marshalThreadItems.Dequeue();
item.Action();
}
else
{
Monitor.Wait(queueLockObj);
}
} while (!disposing);
}
}
And I Execute an Action like this:
private void ExecuteMTAAction(Action action)
{
if (IsMTAThread)
action();
else
{
lock (queueLockObj)
{
MarshalThreadItem item = new MarshalThreadItem();
item.Action = action;
marshalThreadItems.Enqueue(item);
Monitor.Pulse(queueLockObj);
}
}
}
But now I wanted to wait for the finishing the action is called. So I wanted to use a ManuelResetEvent:
private void ExecuteMTAAction(Action action)
{
if (IsMTAThread)
action();
else
{
lock (queueLockObj)
{
MarshalThreadItem item = new MarshalThreadItem();
item.Action = action;
item.waitHandle = new ManualResetEvent(false); //setup
marshalThreadItems.Enqueue(item);
Monitor.Pulse(queueLockObj); //here the pulse does not pulse my backgrond thread anymore
item.waitHandle.WaitOne(); //waiting
}
}
}
And my background thread i just edit like this:
item.Action();
item.waitHandle.Set();
The problem is that the background thread does not get pulsed anymore and just keeps waiting (Monitor.Wait(queueLockObj)) and my mainthread that calls the action waits on the manuelresetevent...?
Why?
Problem in your code is that before Monitor.Wait(queueLockObj) will exit and thread can process item another thread (ExecuteMTAAction method) must call Monitor.Exit(queueLockObj), but call to item.waitHandle.WaitOne() is preventing this call - and you have dead lock. So - you must call Monitor.Exit(queueLockObj) before item.waitHandle.WaitOne().
This code will work fine:
private void ExecuteMTAAction(Action action)
{
if (IsMTAThread)
action();
else
{
lock (queueLockObj)
{
MarshalThreadItem item = new MarshalThreadItem();
item.Action = action;
item.waitHandle = new ManualResetEvent(false); //setup
marshalThreadItems.Enqueue(item);
Monitor.Pulse(queueLockObj);
}
item.waitHandle.WaitOne(); //waiting
}
}