An empty lock to guarantee thread completion - c#

My c# service looks like this:
public partial class MyService : ServiceBase
{
private object #lock = new object();
private CancellationTokenSource cancellationSource = new CancellationTokenSource();
private Timer timer = new Timer(Worker, null, 0, 20*1000);
private void Worker(Object stateInfo)
{
lock (#lock) {
if (cancellationSource.IsCancellationRequested)
return;
//code that must not execute after OnStop
}
}
protected override void OnStop()
{
cancellationSource.Cancel();
lock (#lock) {}
//Worker is guaranteed not to execute any more code here
}
}
As you can see, Worker should not run any more code after OnStop, and I think the empty lock sorts that out, since even if the Worker enters the lock after it, it will immediately exit, due to the cancellation token.
However I have never seen an empty lock, so I'm concerned I missed something. Did I?

The lock serves no goal here. What you are trying to achieve can be done better by using Task:
Task.Run(Worker, cancellationToken);
If the timer is hit, the cancellation token will immediate stop the task from running further.

Related

Is there a way to get a notification, when the main thread stops in C#

I'm writing an application that uses a separate thread for logging.
I'd like to stop the separate thread when the main thread stops. However I'm unable to figure out when to stop the logger thread exactly as I don't know when the main thread stops. Is there a mechanism in C# that would send a notification when the main thread stops? (Or can you think about another solution to my problem?)
// This class automatically applies on each call of every method of Main() function
public class CommandLoggingAdvice : IMethodInterceptor
{
private static ProducerConsumerClass LoggingQueue = ProducerConsumerClass.Instance;
LoggingQueue.AddTask("Logging message on call of *method*");
}
public sealed class ProducerConsumerClass
{
// here Iget an instance of log4net
private ILog _Logger = null;
protected ILog Logger
{
_Logger = LogManager.GetLogger("Logger1");
}
private BlockingCollection<string> tasks = new BlockingCollection<string>();
private static volatile ProducerConsumerClass _instance;
Thread worker;
private Thread mainthread;
private ProducerConsumerClass()
{
mainthread = Thread.CurrentThread;
worker = new Thread(Work);
worker.Name = "Queue thread";
worker.IsBackground = false;
worker.Start(mainthread);
}
public static ProducerConsumerClass Instance
{
get
{
if (_instance == null)
{
_instance = new ProducerConsumerClass();
}
}
}
public void AddTask(string task)
{
tasks.Add(task);
}
void Work(object mainthread)
{
Thread ma = (Thread) mainthread;
if(ma.ThreadState != ThreadState.Stopped)
{
tasks.CompleteAdding();
}
while (true)
{
string task = null;
if (!tasks.IsCompleted)
{
task = tasks.Take();
Logger1.Info(task);
}
else
{
return;
}
}
}
}
If BlockingCollection is empty and application is still working, loop calls one more Take() and result: logger thread is paused now. So when main thread.Threadstate == Stopped, i need to kill logger thread
More info about issue were added in comments
You already have code in the thread that exits if the BlockingCollection is empty and marked as completed. Your loop checks for IsCompleted and exits.
What you need is some way for the main thread to call CompleteAdding on the collection. I would recommend a public method in your ProducerConsumerClass:
public void AllDone()
{
tasks.CompleteAdding();
}
So the main thread can call AllDone when it's done processing. Your thread will then empty the queue and exit.
By the way, a more concise way to write your logging loop is:
foreach (string task in tasks.GetConsumingEnumerable())
{
Logger1.Info(task);
}
This also makes it easier to add cancellation support in the future.

Why Windows.System.Threading.ThreadPoolTimer.Cancel() doesn't work

UPDATE: This works in Windows 10 properly.
Here is a simple example:
void testcase()
{
if (myTimer != null)
myTimer.Cancel();
myTimer = ThreadPoolTimer.CreateTimer(
t => myMethod(),
TimeSpan.FromMilliseconds(4000)
);
}
void myMethod()
{
myTimer = null;
//some work
}
What it should do is ensure that myMethod cannot be called more frequent than once in 4s and that myMethod shouldn't be called if there is already a newer call to testcase. Something similar with .net timers on desktop was possible. However, new call to testcase doesn't prevent previously scheduled myMethods from running. I have a simple workaround by adding integer callid parameter to myMethod and keeping track of it. But this above should work and it doesn't.
Am I doing something wrong? Does anyone have also any better idea on how to do this?
What you're looking for is called debouncing, at least in javascript.
A simple way to achieve it is to use the System.Threading.Timer instead, which has a handy Change used to reset it.
If you want to abstract it into your own timer class, it would look something like:
public class DebounceTimer : IDisposable
{
private readonly System.Threading.Timer _timer;
private readonly int _delayInMs;
public DebounceTimer(Action callback, int delayInMs)
{
_delayInMs = delayInMs;
// the timer is initially stopped
_timer = new System.Threading.Timer(
callback: _ => callback(),
state: null,
dueTime: System.Threading.Timeout.Infinite,
period: System.Threading.Timeout.Infinite);
}
public void Reset()
{
// each call to Reset() resets the timer
_timer.Change(
dueTime: _delayInMs,
period: System.Threading.Timeout.Infinite);
}
public void Dispose()
{
// timers should be disposed when you're done using them
_timer.Dispose();
}
}
Your test case would then become:
private DebounceTimer _timer;
void Init()
{
// myMethod will be called 4000ms after the
// last call to _timer.Reset()
_timer = new DebounceTimer(myMethod, 4000);
}
void testcase()
{
_timer.Reset();
}
void myMethod()
{
//some work
}
public void Dispose()
{
// don't forget to cleanup when you're finished testing
_timer.Dispose();
}
[Update]
From your comments, it seems like you'd like to change the callback method with each reset, and only have the last one invoked. If that's the case, you can change the code to something like:
class DebounceTimer : IDisposable
{
private readonly System.Threading.Timer _timer;
private readonly int _delayInMs;
private Action _lastCallback = () => { };
public DebounceTimer(int delayInMs)
{
_delayInMs = delayInMs;
// the timer is initially stopped
_timer = new System.Threading.Timer(
callback: _ => _lastCallback(),
state: null,
dueTime: System.Threading.Timeout.Infinite,
period: System.Threading.Timeout.Infinite);
}
public void Reset(Action callback)
{
_timer.Change(dueTime: _delayInMs, period: System.Threading.Timeout.Infinite);
// note: no thread synchronization is taken into account here,
// a race condition might occur where the same callback would
// be executed twice
_lastCallback = callback;
}
public void Dispose()
{
_timer.Dispose();
}
}
When calling the Reset method, you can use a lambda to capture various method calls (not only Action methods):
void testcase()
{
_timer.Reset(() => myMethod());
}
void othertestcase()
{
// it's still a parameterless action, but it
// calls another method with two parameters
_timer.Reset(() => someOtherMethod(x, y));
}
As stated in the comments for the second timer snippet, the code is not thread safe, because the timer handler may already be running (or just about to run) on a separate thread while the callback reference is being changed inside the Reset method, meaning that the same callback would be executed twice.
A slightly more complex solution would be to lock while changing the callback, and make an additional check if enough time has elapsed since the last call to reset. The final code would then look like this (there might be other ways to synchronize, but this one is pretty straightforward imho):
class DebounceTimer : IDisposable
{
private readonly System.Threading.Timer _timer;
private readonly int _delayInMs;
private readonly object _lock = new object();
private DateTime _lastResetTime = DateTime.MinValue;
private Action _lastCallback = () => { };
public DebounceTimer(int delayInMs)
{
_delayInMs = delayInMs;
// the timer is initially stopped
_timer = new System.Threading.Timer(
callback: _ => InvokeIfTimeElapsed(),
state: null,
dueTime: System.Threading.Timeout.Infinite,
period: System.Threading.Timeout.Infinite);
}
private void InvokeIfTimeElapsed()
{
Action callback;
lock (_lock)
{
// if reset just happened, skip the whole thing
if ((DateTime.UtcNow - _lastResetTime).TotalMilliseconds < _delayInMs)
return;
else
callback = _lastCallback;
}
// if we're here, we are sure we've got the right callback - invoke it.
// (even if reset happens now, we captured the previous callback
// inside the lock)
callback();
}
public void Reset(Action callback)
{
lock (_lock)
{
// reset timer
_timer.Change(
dueTime: _delayInMs,
period: System.Threading.Timeout.Infinite);
// save last reset timestamp
_lastResetTime = DateTime.UtcNow;
// set the new callback
_lastCallback = callback;
}
}
public void Dispose()
{
_timer.Dispose();
}
}
The problem is that you are setting timer = null in myMethod. That guarantees that it will be null in the next call to testCase (so it won't be cancelled).
Instead, use TimerPool.CreateTimer to create a single-instance timer. It will only fire once. When your worker process finishes, the last thing it should do is initialize a new timer.
To answer my self what is likely the problem, it seems that Cancel() is used only to cancel periodic timer from further repeating. I can't say that documentation says exactly that, but it seems that it is working like that. Thus if timer is not periodic like in this case, Cancel has no effect.
UPDATE: this works in Windows 10 as it should.

AutoResetEvent Reset immediately after Set

Consider the following pattern:
private AutoResetEvent signal = new AutoResetEvent(false);
private void Work()
{
while (true)
{
Thread.Sleep(5000);
signal.Set();
//has a waiting thread definitely been signaled by now?
signal.Reset();
}
}
public void WaitForNextEvent()
{
signal.WaitOne();
}
The purpose of this pattern is to allow external consumers to wait for a certain event (e.g. - a message arriving). WaitForNextEvent is not called from within the class.
To give an example that should be familiar, consider System.Diagnostics.Process. It exposes an Exited event, but it also exposes a WaitForExit method, which allows the caller to wait synchronously until the process exits. this is what I am trying to achieve here.
The reason I need signal.Reset() is that if a thread calls WaitForNextEvent after signal.Set() has already been called (or in other words, if .Set was called when no threads were waiting), it returns immediately, as the event has already been previously signaled.
The question
Is it guaranteed that a thread calling WaitForNextEvent() will be signaled before signal.Reset() is called? If not, what are other solutions for implementing a WaitFor method?
Instead of using AutoResetEvent or ManualResetEvent, use this:
public sealed class Signaller
{
public void PulseAll()
{
lock (_lock)
{
Monitor.PulseAll(_lock);
}
}
public void Pulse()
{
lock (_lock)
{
Monitor.Pulse(_lock);
}
}
public void Wait()
{
Wait(Timeout.Infinite);
}
public bool Wait(int timeoutMilliseconds)
{
lock (_lock)
{
return Monitor.Wait(_lock, timeoutMilliseconds);
}
}
private readonly object _lock = new object();
}
Then change your code like so:
private Signaller signal = new Signaller();
private void Work()
{
while (true)
{
Thread.Sleep(5000);
signal.Pulse(); // Or signal.PulseAll() to signal ALL waiting threads.
}
}
public void WaitForNextEvent()
{
signal.Wait();
}
There is no guarantee. This:
AutoResetEvent flag = new AutoResetEvent(false);
new Thread(() =>
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
Console.WriteLine("Work Item Started");
flag.WaitOne();
Console.WriteLine("Work Item Executed");
}).Start();
// For fast systems, you can help by occupying processors.
for (int ix = 0; ix < 2; ++ix)
{
new Thread(() => { while (true) ; }).Start();
}
Thread.Sleep(1000);
Console.WriteLine("Sleeped");
flag.Set();
// Decomment here to make it work
//Thread.Sleep(1000);
flag.Reset();
Console.WriteLine("Finished");
Console.ReadLine();
won't print "Work Item Executed" on my system. If I add a Thread.Sleep between the Set and the Reset it prints it. Note that this is very processor dependent, so you could have to create tons of threads to "fill" the CPUs. On my PC it's reproducible 50% of the times :-)
For the Exited:
readonly object mylock = new object();
then somewhere:
lock (mylock)
{
// Your code goes here
}
and the WaitForExit:
void WaitForExit()
{
lock (mylock) ;
// exited
}
void bool IsExited()
{
bool lockTacken = false;
try
{
Monitor.TryEnter(mylock, ref lockTacken);
}
finally
{
if (lockTacken)
{
Monitor.Exit(mylock);
}
}
return lockTacken;
}
Note that the lock construct isn't compatible with async/await (as aren't nearly all the locking primitives of .NET)
I would use TaskCompletionSources:
private volatile TaskCompletionSource<int> signal = new TaskCompletionSource<int>();
private void Work()
{
while (true)
{
Thread.Sleep(5000);
var oldSignal = signal;
signal = new TaskCompletionSource<int>()
//has a waiting thread definitely been signaled by now?
oldSignal.SetResult(0);
}
}
public void WaitForNextEvent()
{
signal.Task.Wait();
}
By the time that the code calls SetResult, no new code entering WaitForNextEvent can obtain the TaskCompletionSource that is being signalled.
I believe it is not guaranteed.
However, your logic flow is not understood by me. If your main thread Sets the signal, why should it wait until that signal reaches its destination? Wouldn't it be better to continue your "after signal set" logic in that thread which was waiting?
If you cannot do that, I recommend you to use second WaitHandle to signal the first thread that the second one has reveiced the signal. But I cannot see any pros of such a strategy.

Preventing threads from processing further once call to stop is being made

I have a windows service which will start and stop the execution of some process that is being done with the held of Threads.
I have two classes as follows:
public class PerformTask
{
Thread _thread = null;
public void StartTask()
{
_thread = new Thread(new ThreadStart(DoSomeWork));
_thread.Start();
}
public void DoSomeWork()
{
// Do Some Work
_thread = null;
}
public void Abort()
{
if (_thread != null)
{
try
{
_thread.Abort();
}
catch (ThreadAbortException) {}
}
}
}
public class Engine
{
List<PerformTask> _task = new List<PerformTask>();
public void Start()
{
var task = new PerformTask();
_task.Add(task);
// Add task to the timed action queue
_actionQueue.Add(s => task.StartTask(), TimeSpan.FromSeconds(10));
}
public void Stop()
{
_task.ForEach(task => task.Abort());
_task.Clear();
_actionQueue.Stop();
_actionQueue.Clear();
}
}
The _actionQueue is a custom defined source code developed to perform a specified action at a recurring time interval specified. All the actions are kept in queue and invoked at the specified time interval.
Now, the Windows service's OnStart and OnStop method would call Engine class' Start and Stop method respectively.
What I want is when the windows service is stopped, all the threads that are running should stop their processing/execution.
But, what is happening here is as new thread instance is being created in I have a windows service which will start and stop the execution of some process that is being done with the held of Threads.
I have two classes as follows:
public class PerformTask
{
Thread _thread = null;
public void StartTask()
{
_thread = new Thread(new ThreadStart(DoSomeWork));
_thread.Start();
}
public void DoSomeWork()
{
// Do Some Work
_thread = null;
}
public void Abort()
{
if (_thread != null)
{
try
{
_thread.Abort();
}
catch (ThreadAbortException) {}
}
}
}
public class Engine
{
List<PerformTask> _task = new List<PerformTask>();
ActionQueue _actionQueue = new ActionQueue();
public void Start()
{
foreach(.....)
{
var task = new PerformTask();
_task.Add(task);
// Add task to the timed action queue
_actionQueue.Add(s => task.StartTask(), TimeSpan.FromSeconds(10));
}
_actionQueue.Start();
}
public void Stop()
{
_task.ForEach(task => task.Abort());
_task.Clear();
_actionQueue.Stop();
_actionQueue.Clear();
}
}
The ActionQueue is a custom defined source code developed to perform a specified action at a recurring time interval specified. All the actions are kept in queue and invoked at the specified time interval.
Now, the Windows service's OnStart and OnStop method would call Engine class' Start and Stop method respectively.
What I want is when the windows service is stopped, all the threads that are running should stop their processing/execution.
But, what is happening here is as new thread instance is being created in StartTask method, when I call the
_task.ForEach(task => task.Abort())
I do not have the correct instance of Thread, that is all the instance of
_thread = new Thread(....);
is not being accessed, as there would a multiple queues for the same PerformTask class.
Note: I cannot make changes to the ActionQueue.
Is Abort method a correct way of stopping the threads?
How can I stop all the threads (including all the instances of Thread class created by the source code)?
Usually you'd create a WaitHandle (a ManualResetEvent for example) like that:
ManualResetEvent stopAllThreads = new ManualResetEvent(false);
So the event is "not set". Change the loops in your thread method so that they loop until all work is done or the manual reset event is set.
while (!stopAllThreads.WaitOne(50))
or similar.
Then, in the service's OnStop method, you simply set the event (don't forget to reset it again in OnStart, otherwise the threads will not run again when the service is restarted):
stopAllThreads.Set();
and wait for all the threads to finish.
Actually, aborting threads is not a good way to stop threads - you should always go for something like the above.

Object lock is not working for Thread Safety

I was testing thread-safety for better grasp and this is what I did :
I have a Type called ThreadSample which has two methods and this where locking is happening :
internal class ThreadTime
{
public void doSomething(string message)
{
lock (this)
{
DialogResult t = MessageBox.Show(message);
Thread.Sleep(2000);
}
}
public void anotherLife(string message)
{
MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message);
}
}
Basically the idea is when doSomething() is called, it should lock the entire objects and other threads can even invoke anotherLife method since they are waiting for other threads to release the lock.
This is the logic to simulate lock-release :
public partial class Form1 : Form
{
private ThreadTime time;
private Thread thread;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(workerThread));
time = new ThreadTime();
}
private void button1_Click(object sender, EventArgs e)
{
thread.Start();
//Thread.Sleep(1000);
time.anotherLife("Current thread is = " + "UI Thread");
}
private void workerThread()
{
//time.doSomething("Current thread is = " + Thread.CurrentThread.ManagedThreadId);
time.doSomething("Worker Thread");
}
}
As you can see in the code right below :
When Form is being initialized, a new Thread and ThreadSample are created. Then when user clicks on the button1, thread is started and the UIThread is reaching and invoking anotherLife which is not thread-safe at first.
Anyways, the output is :
There are two MessageBox shown at the same time.
What I was expecting is when the new Thread invokes doSomething(), it gets the lock of the object and UIThread waits for the lock to be released to be able to invoke anotherLife method.
Can some one explain why?
Thanks.
What I was expecting is when the new Thread invokes doSomething(), it gets the lock of the object and UIThread waits for the lock to be released to be able to invoke anotherLife method.
UIThread won't wait for a lock to be released before allowing anotherLife to proceed because anotherLife is not performing a lock. Both threads have to run into a lock statement (locking on the same object) in order to get the behavior you're looking for. Try modifying it to something like:
public void anotherLife(string message)
{
lock (this)
{
MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message);
}
}
Well, lock(this) or lock(someThing) can be a bit of a misleading metaphor.
There is nothing being done 'to' this, but rather the argument to lock is used as a token. All threads accessing a specific resource must use the same token (object) to request access, otherwise your code is broken.
That is why frequently a helper object is used:
private List<string> myList = ...;
private object myLock = new object();
lock(myLock)
{
myList.Add("foo");
}
This scheme only works if all threads lock on myLock before changing myList.
It is considered a 'best practice` because it is not guaranteed that a List<> is safe to lock on.
Only your thread observes the lock
You need to change
private void button1_Click(object sender, EventArgs e)
{
thread.Start();
//Thread.Sleep(1000);
time.anotherLife("Current thread is = " + "UI Thread");
}
to
private void button1_Click(object sender, EventArgs e)
{
thread.Start();
//Thread.Sleep(1000);
lock(time)
{
time.anotherLife("Current thread is = " + "UI Thread");
}
}
Based on your code, it seems you think putting a lock on an object means that object can't be accessed by anything else. That is not the case. A lock on an object just means another lock may not be put on the object until the first lock is released.
You access the object from two places in your code, one in the thread and the other in the button event. You need a lock in both places.

Categories

Resources