This is a separate question based off of this question. To recap, say I have two functions that manipulate a count, and an OnTimer function that fires at a regular interval. My desire is that if/when OverwriteCount is called, IncrementCount can't be executed until the timer function executes.
The proposed solution was:
private int _myCount = 0;
private readonly object _sync = new object();
private ManualResetEventSlim mre = new ManualResetEventSlim(initialState: true);
void IncrementCount()
{
mre.Wait(); // all threads wait until the event is signaled
lock (_sync)
{
_myCount++;
}
}
void OverwriteCount(int newValue)
{
lock (_sync)
{
mre.Reset(); // unsignal the event, blocking threads
_myCount = newValue;
}
}
void OnTimer()
{
lock (_sync)
{
Console.WriteLine(_myCount);
mre.Set(); // signal the event
}
}
The ManualResetEventSlim tries to ensure that once OverwriteCount() unsignals the event, any modifications to _myCount must wait until OnTimer() executes.
Problem:
Say thread A enters IncrementCount() and passes the event's wait() - the ManualResetEvent's initial state is already signaled.
Thread B then starts and executes all of OverwriteCount().
Thread A then continues by acquiring the lock and incrementing _myCount.
This violates my goal as _myCount would change after a call to OverwriteCount(), prior to OnTimer running.
Rejected Alternative: I could move mre.Wait() within lock(_sync) but that poses a deadlock risk. If thread A calls IncrementCount() and blocks on the wait, no other threads can acquire the lock to release it.
Question: Do I need a different synchronization primitive to achieve my goal? Alternatively, am I wrong about the thread safety concern?
I think you can achieve your goal with just the standard Monitor and an additional flag.
private readonly object _sync = new object();
private int _myCount = 0;
private bool _canIncrement = true;
void IncrementCount()
{
lock (_sync)
{
// If the flag indicates we can't increment, unlock _sync and wait for a pulse.
// Use a loop here to ensure that if Wait() returns following the PulseAll() below
// (after re-acquiring the lock on _sync), but a call to OverwriteCount managed to
// occur in-between, that we wait again.
while (!_canIncrement)
{
Monitor.Wait(_sync);
}
_myCount++;
}
}
void OverwriteCount(int newValue)
{
lock (_sync)
{
_canIncrement = false;
_myCount = newValue;
}
}
void OnTimer()
{
lock (_sync)
{
Console.WriteLine(_myCount);
_canIncrement = true;
// Ready any threads waiting on _sync in IncrementCount() above
Monitor.PulseAll(_sync);
}
}
Related
Say I have two functions that manipulate a count, and an OnTimer function that fires at a regular interval.
void IncrementCount()
{
_myCount++;
}
void OverwriteCount(int newValue)
{
_myCount = newValue;
}
void OnTimer()
{
Console.WriteLine(_myCount);
}
My desire is that if/when OverwriteCount is called, IncrementCount can't be executed until the timer function executes.
My initial thought to resolve this was to use a ManualResetEvent to help synchronize behaviors:
private static ManualResetEventSlim mre = new ManualResetEventSlim(initialState: true);
void IncrementCount()
{
mre.Wait(-1); // can't increment until the event is signaled
_myCount++;
}
void OverwriteCount(int newValue)
{
mre.Reset(); // unsignal the event, blocking threads
_myCount = newValue;
}
void OnTimer()
{
Console.WriteLine(_myCount);
mre.Set(); // signal the event
}
My concern is a degenerate, multi-threaded scenario where thread A gets past the mre.Wait() in IncrementCount() but hasn't actually incremented _myCount yet. Thread B then calls mre.Reset() and overwrites _myCount. Thread A then gets a turn and increments _myCount.
Could I solve this by also adding a lock inside IncrementCount() and OverwriteCount() to ensure only one thread can modify _myCount at a time? Do I risk deadlock if I get stuck waiting on the reset event while holding the lock?
If i understand you, then yes it would work if you chose what to lock appropriately. There is probably a more granular way to do this, but as of now i see nothing wrong with this
void IncrementCount()
{
mre.Wait();
// lets not cause a race, lock until OverwriteCount is finished
lock (_sync)
{
_myCount++;
}
}
void OverwriteCount(int newValue)
{
// lock this so we can assure the count is updated
lock (_sync)
{
mre.Reset(); // unsignal the event, blocking threads
_myCount = newValue;
}
}
void OnTimer()
{
Console.WriteLine(_myCount);
mre.Set(); // signal the event
}
islem = new Thread(new ThreadStart(ilk));
islem2 = new Thread(new ThreadStart(ikinci));
islem3 = new Thread(new ThreadStart(ucuncu));
islem4 = new Thread(new ThreadStart(dorduncu));
islem.Start();
islem2.Start();
islem3.Start();
islem4.Start();
if (!islem.IsAlive)
{
islem2.Suspend();
islem3.Suspend();
islem4.Suspend();
}
I want to do when islem is done. Other threads suspend but it doesn't work
I read about ManualResetEvent but I can't figure out multi-threading examples.They works just one thread simples. Also I read http://www.albahari.com/threading/part4.aspx#_Suspending_and_Resuming this paper to and look similar questions like C# controlling threads (resume/suspend) How to pause/suspend a thread then continue it? Pause/Resume thread whith AutoResetEvent I am working multi - thread objects
If you just need to cancel the worker threads, the very simplest approach is to use a flag. You have to mark the flag volatile to ensure all threads are using the same copy.
private volatile bool _done = false;
void Main()
{
StartWorkerThreads();
}
void WorkerThread()
{
while (true)
{
if (_done) return; //Someone else solved the problem, so exit.
ContinueSolvingTheProblem();
}
_done = true; //Tell everyone else to stop working.
}
If you truly want to pause (I'm not sure why) you can use a ManualResetEvent. This allows blocking behavior without consuming resources for the paused thread.
//When signalled, indicates threads can proceed.
//When reset, threads should pause as soon as possible.
//Constructor argument = true so it is set by default
private ManualResetEvent _go = new ManualResetEvent(true);
void Main()
{
StartWorkerThreads();
}
void WorkerThread()
{
while (true)
{
_go.WaitOne(); //Pause if the go event has been reset
ContinueSolvingTheProblem();
}
_go.Reset(); //Reset the go event in order to pause the other threads
}
You can also combine the approaches, e.g. if you wanted to be able to pause the threads, do some more work, then cancel them:
private volatile bool _done = false;
private ManualResetEvent _go = new ManualResetEvent(true);
void Main()
{
StartWorkerThreads();
}
void WorkerThread()
{
while (true)
{
if (_done) return; //Exit if problem has been solved
_go.WaitOne(); //Pause if the go event has been reset
if (_done) return; //Exit if problem was solved while we were waiting
ContinueSolvingTheProblem();
}
_go.Reset(); //Reset the go event in order to pause the other threads
if (VerifyAnswer())
{
_done = true; //Set the done flag to indicate all threads should exit
}
else
{
_go.Set(); //Tell other threads to continue
}
}
Assume we have this event attached to the timer event handler.
private void TimerTick(object sender, ElapsedEventArgs e)
{
if(_gaurd) return;
lock (this) // lock per instance
{
_gaurd = true;
if (!_timer.Enabled) return;
OnTick(); // somewhere inside here timer may pause it self.
_gaurd = false;
}
}
Now there two things that can pause this timer. One is user request from UI thread, second is the timer which may pause it self.
If the timer pause it self we can guarantee the pause will complete before we continue.
timer.Stop();
OnPause(); // timer must be paused because OnPause() is not thread safe.
But if the user, requests for timer pause the request is from another thread and we can not guarantee timer is fully paused or not.
timer.Stop();
OnPause(); // timer event may be still inside OnTick() and may conflict with OnPause()
-------------------------------------------------------------------------------------------------------
So I'm looking for a way to make this thread safe. This is what I have tried so far but I'm not sure if this works in all situations or not.
Its looking good but want to make sure that if there is anything I'm not aware of. or maybe to know if there are better ways to make this process thread safe.
I have tried to separate user request from Inner workings of timer. therefore I have two Pause methods for my timer.
public class Timer
{
internal void InternalStop() // must be called by timer itself.
{
timer.Pause(); // causes no problem
}
public void Stop() // user request must come here. (if timer call this deadlock happens)
{
InternalStop();
lock (this) // reference of timer
{
// do nothing and wait for OnTick().
}
}
}
This is not actual code but behavior is same. it should illustrate that this class is not thread safe. :
public class WorkingArea
{
private List<Worker> _workers;
public void OnTick()
{
foreach(var worker in _workers)
{
worker.Start();
}
if(_workers.TrueForAll(w => w.Ends))
{
PauseTimer();
}
}
public void OnPause() // after timer paused
{
foreach(var Worker in _workers)
{
worker.Stop();
}
}
}
My timer was already thread safe.
it was all about the fact that I didn't know about Re-entrant locks
So if user from another thread request to pause timer , lock will work just fine and will block until timer is fully paused.
If the timer internally pauses it self it wont deal lock. because its in the same thread the lock was acquired.
public class Timer
{
private timer = new System.Timers.Timer();
private bool _guard = false;
// stops the timer and waits until OnTick returns and lock releases.
// timer can safely pause it self within OnTick.
// if user request to pause from another thread, full pause is ensured
public void Stop()
{
timer.Pause();
lock (this) // reference of timer. it wont dead lock
{
// do nothing and wait for OnTick().
}
}
private void TimerTick(object sender, ElapsedEventArgs e)
{
if(_gaurd) return;
lock (this) // lock per instance
{
_gaurd = true;
if (!_timer.Enabled) return;
OnTick(); // somewhere inside here timer may pause it self.
_gaurd = false;
}
}
}
I have a problem with C# threads.
I have eendless process “worker”, which do some and after iteration sleep 3 seconds.
I have a timer function that runs at a given time.
I need the "timer function" do something, then wait for the end "worker" iteration and then pause "worker" until "timer function" is done own task , after that timer function starts a "worker" again.
How can I do that?
Best regards Paul
You could use wait handles to control the methods - something like:
private AutoResetEvent mWorkerHandle = new AutoResetEvent(initialState: false);
private AutoResetEvent mTimerHandle = new AutoResetEvent(initialState: false);
// ... Inside method that initializes the threads
{
Thread workerThread = new Thread(new ThreadStart(Worker_DoWork));
Thread timerThread = new Thread(new ThreadStart(Timer_DoWork));
workerThread.Start();
timerThread.Start();
// Signal the timer to execute
mTimerHandle.Set();
}
// ... Example thread methods
private void Worker_DoWork()
{
while (true)
{
// Wait until we are signalled
mWorkerHandle.WaitOne();
// ... Perform execution ...
// Signal the timer
mTimerHandle.Set();
}
}
private void Timer_DoWork()
{
// Signal the worker to do something
mWorkerHandle.Set();
// Wait until we get signalled
mTimerHandle.WaitOne();
// ... Work has finished, do something ...
}
This should give you an idea of how to control methods running on other threads by way of a WaitHandle (in this case, an AutoResetEvent).
You can use a lock to pause a thread while another is doing something:
readonly object gate = new object();
void Timer()
{
// do something
...
// wait for the end "worker" iteration and then
// pause "worker" until "timer function" is done
lock (gate)
{
// do something more
...
}
// start the "worker" again
}
void Worker()
{
while (true)
{
lock (gate)
{
// do something
...
}
Thread.Sleep(3000);
}
}
Do you need paralel work of Worker and another operation? If not, You can do somthing similar:
EventWaitHandle processAnotherOperationOnNextIteration = new EventWaitHandle(false, EventResetMode.ManualReset);
Worker()
{
while(true)
{
doLongOperation();
if (processAnotherOperationOnNextIteration.WaitOne(0))
{
processAnotherOperationOnNextIteration.Reset();
doAnotherOperation();
}
Thread.Sleep(3000);
}
}
in timer
void Timer()
{
processAnotherOperationOnNextIteration.Set();
}
Problem statement
I have a worker thread that basically scans a folder, going into the files within it, and then sleeps for a while. The scanning operation might take 2-3 seconds but not much more. I'm looking for a way to stop this thread elegantly.
Clarification: I want to stop the thread while it's sleeping, and not while it's scanning. However, the problem is that I do not know what is the current state of the thread. If it's sleeping I want it to exit immediately. If it's scanning, I want it to exit the moment it tries to block.
Attempts at a solution
At first I was using Sleep and Interrupt. Then I found out that Interrupt doesn't really interrupt the Sleep - it only works when the threads TRIES to go into sleeping.
So I switched to Monitor Wait&Pulse. Then I found out that the Pulse only works when I'm actually in the Wait. So now I have a thread which looks like that:
while (m_shouldRun)
{
try
{
DoSomethingThatTakesSeveralSeconds();
lock (this)
{
Monitor.Wait(this, 5000);
}
}
catch (ThreadInterruptedException)
{
m_shouldRun = false;
}
}
And now I need to craft my Stop function. So I started with:
public void Stop()
{
m_shouldRun = false;
lock (this)
{
Monitor.Pulse(this);
}
thread.Join();
}
But this doesn't work because I may be pulsing while the thread works (while it's not waiting). So I added Interrupt:
public void Stop()
{
m_shouldRun = false;
thread.Interrupt();
lock (this)
{
Monitor.Pulse(this);
}
thread.Join();
}
Another option is to use:
public void Stop()
{
m_shouldRun = false;
while (!thread.Join(1000))
{
lock (this)
{
Monitor.Pulse(this);
}
}
}
The question
What is the preferred method? Is there a third method which is preferable?
Another alternative is to use events:
private ManualResetEvent _event = new ManualResetEvent(false);
public void Run()
{
while (true)
{
DoSomethingThatTakesSeveralSeconds();
if (_event.WaitOne(timeout))
break;
}
}
public void Stop()
{
_event.Set();
thread.Join();
}
The way to stop a thread elegantly is to leave it finish by itself. So inside the worker method you could have a boolean variable which will check whether we want to interrupt. By default it will be set to false and when you set it to true from the main thread it will simply stop the scanning operation by breaking from the processing loop.
I recommend to keep it simple:
while (m_shouldRun)
{
DoSomethingThatTakesSeveralSeconds();
for (int i = 0; i < 5; i++) // example: 5 seconds sleep
{
if (!m_shouldRun)
break;
Thread.Sleep(1000);
}
}
public void Stop()
{
m_shouldRun = false;
// maybe thread.Join();
}
This has the following advantages:
It smells like busy waiting, but it's not. $NUMBER_OF_SECONDS checks are done during the waiting phase, which is not comparable to the thousands of checks done in real busy waiting.
It's simple, which greatly reduces the risk of error in multi-threaded code. All your Stop method needs to do is to set m_shouldRun to false and (maybe) call Thread.Join (if it is necessary for the thread to finish before Stop is left). No synchronization primitives are needed (except for marking m_shouldRun as volatile).
I came up with separately scheduling the task:
using System;
using System.Threading;
namespace ProjectEuler
{
class Program
{
//const double cycleIntervalMilliseconds = 10 * 60 * 1000;
const double cycleIntervalMilliseconds = 5 * 1000;
static readonly System.Timers.Timer scanTimer =
new System.Timers.Timer(cycleIntervalMilliseconds);
static bool scanningEnabled = true;
static readonly ManualResetEvent scanFinished =
new ManualResetEvent(true);
static void Main(string[] args)
{
scanTimer.Elapsed +=
new System.Timers.ElapsedEventHandler(scanTimer_Elapsed);
scanTimer.Enabled = true;
Console.ReadLine();
scanningEnabled = false;
scanFinished.WaitOne();
}
static void scanTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
scanFinished.Reset();
scanTimer.Enabled = false;
if (scanningEnabled)
{
try
{
Console.WriteLine("Processing");
Thread.Sleep(5000);
Console.WriteLine("Finished");
}
finally
{
scanTimer.Enabled = scanningEnabled;
scanFinished.Set();
}
}
}
}
}