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?
Related
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
}
I want when i click thread.Abort() and thread finish print label after that it will abort. It only abort thread when finish current job. Thanks
namespace ThreadTest
{
public partial class Form1 : Form
{
Thread thread;
bool loop = true;
Stopwatch regularSW = new Stopwatch();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(() => threadtest()));
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread.Abort();
}
public void threadtest()
{
while (loop)
{
regularSW.Start();
Thread.Sleep(5000);
regularSW.Stop();
this.Invoke(new Action(() => label1.Text += "Sleep in: " + regularSW.Elapsed + Environment.NewLine));
}
}
}
}
Thread.Abort is a request, the operating system and thread are free to ignore it in situations where an abort is not possible. Generally, Abort should never be used in "by design" scenarios. Instead, your loop should check to see if there is a cancel action pending, perhaps something like this:
Thread thread;
bool loop = true;
volatile bool _cancelPending = false;
Stopwatch regularSW = new Stopwatch();
//Snip... unchanged code removed for brevity.
private void button2_Click(object sender, EventArgs e)
{
_cancelPending = true;
}
public void threadtest()
{
while (loop)
{
if (_cancelPending) break;
regularSW.Start();
Thread.Sleep(5000);
regularSW.Stop();
this.Invoke(new Action(() => label1.Text += "Sleep in: " + regularSW.Elapsed + Environment.NewLine));
}
}
Perhaps that is the purpose of your loop field, but I introduced another field, _cancelPending, in-case it is serving a different purpose.
Aborting a thread is not something you should need to do in most applications; when the thread no longer has work to do, it will stop as a natural part of its lifecycle.
To allow this to happen, your code needs to signal that the method should stop executing. In .NET, the type CancellationTokenSource is used to allow thread-safe signalling that an operation should be stopped.
However, the most prominent concern is that your thread spends most of its time sleeping. This means that when the Cancel button is pressed, you must wait for the thread to wake up before it will notice that cancellation has been requested.
We can use the cancellation mechanism to simulate the thread sleeping by having it wait for a period of time, or for cancellation to be requested - whichever happens first:
Thread thread;
CancellationTokenSource cts;
Stopwatch regularSW = new Stopwatch();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
thread = new Thread(new ThreadStart(() => threadtest(cts.Token)));
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
cts.Cancel();
}
public void threadtest(CancellationToken cancellation)
{
while (!cancellation.IsCancellationRequested)
{
regularSW.Start();
// Simulate a Thread.Sleep; returns true if cancellation requested.
if (!cancellation.WaitHandle.WaitOne(5000))
{
regularSW.Stop();
this.Invoke(() => label1.Text += "Sleep in: "
+ regularSW.Elapsed
+ Environment.NewLine);
}
}
}
I have this simple piece of code:
private volaile bool working;
private volatile List<Thread> threads = new List<Thread>();
private volatile Form Face;
public void Start(int n)
{
working = true;
for (int i = 0; i <= n; i++)
{
Thread worker = new Thread(() =>
{
while(working)
{
// do some work
}
});
threads.Add(worker);
worker.Start();
}
}
public void Stop()
{
if(working)
{
working = false;
logger.Info("Waiting threads join");
foreach (Thread worker in threads)
{
worker.Join();
}
logger.Info("Threads joined");
}
}
private void Face_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Face.Invoke(new Action(() => {Stop();}));
System.Environment.Exit(0);
}
Face form creates on programm start and have some controls, so when I use Start() and Stop() methods, everything works fine (all threads join normally).
But when I press "X" Form button, programm stacks on "Waiting threads join". Why? What am I missing?
Thread sample = new Thread(new ThreadStart(Thread1));
sample.IsBackground= true;
try to set the threads as background threads.
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'm learning about threads in C#, and i get this behavior that i cant understand.
The code simulates I/O operations, like files or serial port, where only one thread can access it at time, and it blocks until finishes.
Four threads are started. Each performs just a count. It works ok, i can see on the form the counts growing. But there is a button to count from the form thread. When i push it, the main thread freezes. The debugger shows that the others threads keep counting, one by one, but the form thread never gets access to the resource.
1) Why the lock(tty) from the form thread never gets access to it, when the others threads has no problem ?
2) Is there a better way to do this type of synchronization ?
Sorry about the big code:
public class MegaAPI
{
public int SomeStupidBlockingFunction(int c)
{
Thread.Sleep(800);
return ++c;
}
}
class UIThread
{
public delegate void dlComandoMaquina();
public class T0_SyncEvents
{
private EventWaitHandle _EventFechar; // Exit thread event
public T0_SyncEvents()
{
_EventFechar = new ManualResetEvent(false);
}
public EventWaitHandle EventFecharThread // Exit thread event
{
get { return _EventFechar; }
}
}
public class T0_Thread
{
private T0_SyncEvents _syncEvents;
private int _msTimeOut;
private dlComandoMaquina _ComandoMaquina;
public T0_Thread(T0_SyncEvents e, dlComandoMaquina ComandoMaquina, int msTimeOut)
{
_syncEvents = e;
_msTimeOut = msTimeOut;
_ComandoMaquina = ComandoMaquina;
}
public void VaiRodar() // thread running code
{
while (!_syncEvents.EventFecharThread.WaitOne(_msTimeOut, false))
{
_ComandoMaquina();
}
}
}
}
public partial class Form1 : Form
{
MegaAPI tty;
UIThread.T0_Thread thr1;
UIThread.T0_SyncEvents thrE1;
Thread Thread1;
int ACount1 = 0;
void UIUpdate1()
{
lock (tty)
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
}
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
UIThread.T0_Thread thr2;
UIThread.T0_SyncEvents thrE2;
Thread Thread2;
int ACount2 = 0;
void UIUpdate2()
{
lock (tty)
{
ACount2 = tty.SomeStupidBlockingFunction(ACount2);
}
this.BeginInvoke((Action)delegate { txtAuto2.Text = ACount2.ToString(); });
}
UIThread.T0_Thread thr3;
UIThread.T0_SyncEvents thrE3;
Thread Thread3;
int ACount3 = 0;
void UIUpdate3()
{
lock (tty)
{
ACount3 = tty.SomeStupidBlockingFunction(ACount3);
}
this.BeginInvoke((Action)delegate { txtAuto3.Text = ACount3.ToString(); });
}
UIThread.T0_Thread thr4;
UIThread.T0_SyncEvents thrE4;
Thread Thread4;
int ACount4 = 0;
void UIUpdate4()
{
lock (tty)
{
ACount4 = tty.SomeStupidBlockingFunction(ACount4);
}
this.BeginInvoke((Action)delegate { txtAuto4.Text = ACount4.ToString(); });
}
public Form1()
{
InitializeComponent();
tty = new MegaAPI();
thrE1 = new UIThread.T0_SyncEvents();
thr1 = new UIThread.T0_Thread(thrE1, UIUpdate1, 500);
Thread1 = new Thread(thr1.VaiRodar);
Thread1.Start();
thrE2 = new UIThread.T0_SyncEvents();
thr2 = new UIThread.T0_Thread(thrE2, UIUpdate2, 500);
Thread2 = new Thread(thr2.VaiRodar);
Thread2.Start();
thrE3 = new UIThread.T0_SyncEvents();
thr3 = new UIThread.T0_Thread(thrE3, UIUpdate3, 500);
Thread3 = new Thread(thr3.VaiRodar);
Thread3.Start();
thrE4 = new UIThread.T0_SyncEvents();
thr4 = new UIThread.T0_Thread(thrE4, UIUpdate4, 500);
Thread4 = new Thread(thr4.VaiRodar);
Thread4.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
thrE1.EventFecharThread.Set();
thrE2.EventFecharThread.Set();
thrE3.EventFecharThread.Set();
thrE4.EventFecharThread.Set();
Thread1.Join();
Thread2.Join();
Thread3.Join();
Thread4.Join();
}
int Mcount = 0;
private void btManual_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
lock (tty) // locks here ! Never runs inside! But the other threads keep counting..
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
txtManual.Text = Mcount.ToString();
}
Cursor.Current = Cursors.Default;
}
}
I suspect you are hitting something with the Windows message loop and threading in WinForms. I don't know what that is, but here are a few pointers:
You can run the button's task in a backgroundWorker to keep the work off the UI thread. That solves the lock problem. Drag a BackgroundWorker from the toolbox and drop it on your Form in the designer, and hook up the event, i.e.:
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
then switch your code in btManual_Click to call the background worker like this:
backgroundWorker1.RunWorkerAsync();
and then:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
this.BeginInvoke((Action)delegate { txtManual.Text = Mcount.ToString(); });
}
I've left out the lock (tty) because I would rather see only one of these statements inside the function, rather than five of them outside. And instead of locking on tty, I would create a private variable like this:
public class MegaAPI
{
private object sync = new object();
public int SomeStupidBlockingFunction(int c)
{
lock (this.sync)
{
Thread.Sleep(800);
return ++c;
}
}
}
Everywhere else is then simplified, for example:
void UIUpdate1()
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
And since you can't run the background worker while it's still processing, here is a quick-and-dirty solution: disable the button while it's working:
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
and then:
private void btManual_Click(object sender, EventArgs e)
{
this.btManual.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
and:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.btManual.Enabled = true;
}
So I recommend:
Keep a single lock () statement
inside the function needing the
synchronization
Keep the lock object private
Run the work on a background worker
Mutexes do not provide fairness by default. They just guarantee that your process as a whole will make forward progress. It is the implementation's job to pick the best thread to get the mutex based on characteristics of the scheduler and so on. It is the coder's job to make sure that the thread that gets the mutex does whatever work the program needs done.
If it's a problem for you if the "wrong thread" gets the mutex, you are doing it wrong. Mutexes are for cases where there is no "wrong thread". If you need fairness or predictable scheduling, you need to use a locking primitive that provides it or use thread priorities.
Mutexes tend to act in strange ways when threads that hold them aren't CPU-limited. Your threads acquire the mutex and then deschedule themselves. This will lead to degenerate scheduling behavior just like the behavior you're seeing. (They won't break their guarantees, of course, but they will act much less like a theoretically perfect mutex that also provided things like fairness.)