Wouldn't this be overkill and only one of these necessary? I've searched and found different posts about Mutual Exclusion and locks in C# here and here.
Example:
In our app, we have a function that spins off multiple reconnection threads and inside this thread we use a Mutex and a lock. Wouldn't lock block access to this section of code and prevent connect from being updated by any other thread?
bool connect = false;
Mutex reconnectMutex = new Mutex(false, "Reconnect_" + key);
try
{
lock(site)
{
if(site.ContainsKey(key))
{
siteInfo = (SiteInfo)site[key];
if(reconnectMutex.WaitOne(100, true))
{
connect = true;
}
}
}
if (connect)
{
// Process thread logic
}
}
catch
{}
reconnectMutex.ReleaseMutex();
More Info:
This is in an ASP.NET WebService not running in a Web Garden.
That Mutex (because it has a name) will stop any process on the same machine accessing it as well, whereas lock will only stop other threads in the same process. I can't see from that code sample why you'd need both kinds of lock. It seems good practice to hold the simple lock for a short period of time - but then the much heavier interprocess mutex is locked for a probably longer (though overlapping) period! Would be simpler to just use the mutex. And perhaps to find out whether an interprocess lock is really necessary.
By the way, catch {} is absolutely the wrong thing to use in that scenario. You should use finally { /* release mutex */ }. They are very different. The catch will swallow far more kinds of exception than it should, and will also cause nested finally handlers to execute in response to low-level exceptions such as memory corruption, access violation, etc. So instead of:
try
{
// something
}
catch
{}
// cleanup
You should have:
try
{
// something
}
finally
{
// cleanup
}
And if there are specific exceptions you can recover from, you could catch them:
try
{
// something
}
catch (DatabaseConfigurationError x)
{
// tell the user to configure the database properly
}
finally
{
// cleanup
}
"lock" is basically just a syntactic sugar for Montor.Enter/Exit. Mutex is a multi-process lock.
They have very different behavior. There is nothing wrong with using both in the same application or methods, since they're designed to block different things.
However, in your case, I think you may be better off looking into Semaphore and Monitor. It doesn't sound like you need to lock across processes, so they are probably a better choice in this situation.
As others have pointed out, the Mutex locks across processes and the local lock (Monitor) locks only those threads owned by the current process. However ...
The code you showed has a pretty serious bug. It looks like you're releasing the Mutex unconditionally at the end (i.e. reconnectMutex.ReleaseMutex()), but the Mutex is only acquired if site.ContainsKey() returns true.
So if site.ContainsKey returns false, then releasing the Mutex is going to throw ApplicationException because the calling thread does not own the Mutex.
You didn't give enough info to really answer this. As already stated by Earwicker a Mutex allows you to have a synchronization accross processes. Thus if you have two instances of the same app running you can serialize access. You might do this for example when using external resources.
Now you lock on site protects site from access by other threads in the same process. This might be nessecary depending on what other methods / threads are doing. Now if this is the only place that site is being locked then yes I would think it is overkill.
Related
The true power of semaphore is :
Limits the number of threads that can access a resource or pool of
resources concurrently
That is understood and clear.
But I never got a chance to play with the overload of Wait which accepts a timeout integer, however - this seems to allow multiple threads get into the critical section although I've explicitly set semaphore not to allow more than one thread at a time:
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
private void Main()
{
Task.Run(() => DelayAndIncrementAsync());
Task.Run(() => DelayAndIncrementAsync());
}
private void DelayAndIncrementAsync()
{
_mutex.Wait(2000);
try
{
Console.WriteLine(0);
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine(1);
}
finally
{
_mutex.Release();
}
}
The first thread is entering the mutex zone, prints "0", waits 5 seconds, meanwhile after 2 seconds the other thread ALSO enters the critical section?
Question
Isn't it defeating the whole purpose of semaphore?
What are the real life scenarios which I would use this timeout, especially when the basic rule is -
"Semaphore = Limits the number of threads that can access a resource
or pool of resources concurrently
You need to check the return value of the wait. The Timeout based wait will try for 2 seconds to take the mutex then return. You need to check if the return value is true (i.e you have the mutex) or not.
Edit: Also keep in mind that the timeout based wait will return immediately if the semaphore is available, so you cant use this to prevent an infinite loop in the code via this technique.
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
void Main()
{
Task.Run(()=>DelayAndIncrementAsync());
Task.Run(()=>DelayAndIncrementAsync());
}
public void DelayAndIncrementAsync()
{
if (_mutex.Wait(2000))
{
try
{
Console.WriteLine(0);
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine(1);
}
finally
{
_mutex.Release();
}
} else {
//oh noes I don't have the mutex
}
}
Your misconception is that there is an implicit "mutex zone" which is not defined by you.
The overload of Wait which you are using returns a boolean value which tells you whether or not the mutex was successfully entered.
What you are doing in your example is entering the critical zone whether or not the thread has acquired the mutex, making it redundant.
Generally, you would want to use this overload in any situation where you want to try to enter a mutex but also have a fallback strategy in case that it is not currently possible to acquire the mutex within the allotted time.
This will make people cringe but using the timeout (and confirming it did timeout) is a good way to log and track deadlock bugs. Sure if you wrote your program correctly you wouldn't need these, but I've personally used this for this purpose which has saved me a lot of time.
So yes it does defeat the purpose (in most cases) if you let it timeout and then hit the critical section with multiple threads. But it can be useful to log or detect a deadlock bug.
There are also use cases where you want multiple threads to access the critical section, but only in specific scenarios. Eg it would not be fatal and simply be undesirable for it occur. Eg you aren't using the semaphore to stop a cross thread crash, but rather something else.
Windows service: Generating a set of FileWatcher objects from a list of directories to watch in a config file, have the following requirements:
File processing can be time consuming - events must be handled on their own task threads
Keep handles to the event handler tasks to wait for completion in an OnStop() event.
Track the hashes of uploaded files; don't reprocess if not different
Persist the file hashes to allow OnStart() to process files uploaded while the service was down.
Never process a file more than once.
(Regarding #3, we do get events when there are no changes... most notably because of the duplicate-event issue with FileWatchers)
To do these things, I have two dictionaries - one for the files uploaded, and one for the tasks themselves. Both objects are static, and I need to lock them when adding/removing/updating files and tasks. Simplified code:
public sealed class TrackingFileSystemWatcher : FileSystemWatcher {
private static readonly object fileWatcherDictionaryLock = new object();
private static readonly object runningTaskDictionaryLock = new object();
private readonly Dictionary<int, Task> runningTaskDictionary = new Dictionary<int, Task>(15);
private readonly Dictionary<string, FileSystemWatcherProperties> fileWatcherDictionary = new Dictionary<string, FileSystemWatcherProperties>();
// Wired up elsewhere
private void OnChanged(object sender, FileSystemEventArgs eventArgs) {
this.ProcessModifiedDatafeed(eventArgs);
}
private void ProcessModifiedDatafeed(FileSystemEventArgs eventArgs) {
lock (TrackingFileSystemWatcher.fileWatcherDictionaryLock) {
// Read the file and generate hash here
// Properties if the file has been processed before
// ContainsNonNullKey is an extension method
if (this.fileWatcherDictionary.ContainsNonNullKey(eventArgs.FullPath)) {
try {
fileProperties = this.fileWatcherDictionary[eventArgs.FullPath];
}
catch (KeyNotFoundException keyNotFoundException) {}
catch (ArgumentNullException argumentNullException) {}
}
else {
// Create a new properties object
}
fileProperties.ChangeType = eventArgs.ChangeType;
fileProperties.FileContentsHash = md5Hash;
fileProperties.LastEventTimestamp = DateTime.Now;
Task task;
try {
task = new Task(() => new DatafeedUploadHandler().UploadDatafeed(this.legalOrg, datafeedFileData), TaskCreationOptions.LongRunning);
}
catch {
..
}
// Only lock long enough to add the task to the dictionary
lock (TrackingFileSystemWatcher.runningTaskDictionaryLock) {
try {
this.runningTaskDictionary.Add(task.Id, task);
}
catch {
..
}
}
try {
task.ContinueWith(t => {
try {
lock (TrackingFileSystemWatcher.runningTaskDictionaryLock) {
this.runningTaskDictionary.Remove(t.Id);
}
// Will this lock burn me?
lock (TrackingFileSystemWatcher.fileWatcherDictionaryLock) {
// Persist the file watcher properties to
// disk for recovery at OnStart()
}
}
catch {
..
}
});
task.Start();
}
catch {
..
}
}
}
}
What's the effect of requesting a lock on the FileSystemWatcher collection in the ContinueWith() delegate when the delegate is defined within a lock on the same object? I would expect it to be fine, that even if the task starts, completes, and enters the ContinueWith() before ProcessModifiedDatafeed() releases the lock, the task thread would simply be suspended until the creating thread has released the lock. But I want to make sure I'm not stepping on any delayed execution landmines.
Looking at the code, I may be able to release the lock sooner, avoiding the issue, but I'm not certain yet... need to review the full code to be sure.
UPDATE
To stem the rising "this code is terrible" comments, there are very good reasons why I catch the exceptions I do, and am catching so many of them. This is a Windows service with multi-threaded handlers, and it may not crash. Ever. Which it will do if any of those threads have an unhandled exception.
Also, those exceptions are written to future bulletproofing. The example I've given in comments below would be adding a factory for the handlers... as the code is written today, there will never be a null task, but if the factory is not implemented correctly, the code could throw an exception. Yes, that should be caught in testing. However, I have junior developers on my team... "May. Not. Crash." (also, it must shut down gracefully if there is an unhandled exception, allowing currently-running threads to complete - which we do with an unhandled exception handler set in main()). We have enterprise-level monitors configured to send alerts when application errors appear on the event log – those exceptions will log and flag us. The approach was a deliberate and discussed decision.
Each possible exception has each been carefully considered and chosen to fall into one of two categories - those that apply to a single datafeed and will not shut down the service (the majority), and those that indicate clear programming or other errors that fundamentally render the code useless for all datafeeds. For example, we've chosen to shut down the service down if we can't write to the event log, as that's our primary mechanism for indicating datafeeds are not getting processed. The exceptions are caught locally, because the local context is the only place where the decision to continue can be made. Furthermore, allowing exceptions to bubble up to higher levels (1) violates the concept of abstraction, and (2) makes no sense in a worker thread.
I'm surprised at the number of people who argue against handling exceptions. If I had a dime for every try..catch(Exception){do nothing} I see, you'd get your change in nickels for the rest of eternity. I would argue to the death1 that if a call into the .NET framework or your own code throws an exception, you need to consider the scenario that would cause that exception to occur and explicitly decide how it should be handled. My code catches UnauthorizedExceptions in IO operations, because when I considered how that could happen, I realized that adding a new datafeed directory requires permissions to be granted to the service account (it won't have them by default).
I appreciate the constructive input... just please don't criticize simplified example code with a broad "this sucks" brush. The code does not suck - it is bulletproof, and necessarily so.
1 I would only argue a really long time if Jon Skeet disagrees
First, your question: it's not a problem in itself to request lock inside ContinueWith. If you bother you do that inside another lock block - just don't. Your continuation will execute asynchronously, in different time, different thread.
Now, code itself is questionable. Why do you use many try-catch blocks around statements that almost cannot throw exceptions? For example here:
try {
task = new Task(() => new DatafeedUploadHandler().UploadDatafeed(this.legalOrg, datafeedFileData), TaskCreationOptions.LongRunning);
}
catch {}
You just create task - I cannot imagine when this can throw. Same story with ContinueWith. Here:
this.runningTaskDictionary.Add(task.Id, task);
you can just check if such key already exists. But even that is not necessary because task.Id is unique id for given task instance which you just created. This:
try {
fileProperties = this.fileWatcherDictionary[eventArgs.FullPath];
}
catch (KeyNotFoundException keyNotFoundException) {}
catch (ArgumentNullException argumentNullException) {}
is even worse. You should not use exceptions lile this - don't catch KeyNotFoundException but use appropriate methods on Dictionary (like TryGetValue).
So to start with, remove all try catch blocks and either use one for the whole method, or use them on statements that can really throw exceptions and you cannot handle that situation otherwise (and you know what to do with exception thrown).
Then, your approach to handle filesystem events is not quite scaleable and reliable. Many programs will generate multiple change events in short intervals when they are saving changes to a file (there are also other cases of multiple events for the same file going in sequence). If you just start processing file on every event, this might lead to different kind of troubles. So you might need to throttle events coming for a given file and only start processing after certain delay after last detected change. That might be a bit advanced stuff, though.
Don't forget to grab a read lock on the file as soon as possible, so that other processes cannot change file while you are working with it (for example, you might calculate md5 of a file, then someone changes file, then you start uploading - now your md5 is invalid). Other approach is to record last write time and when it comes to uploading - grab read lock and check if file was not changed in between.
What is more important is that there can be a lot of changes at once. Say I copied 1000 files very fast - you do not want to start uploading them all at once with 1000 threads. You need a queue of files to process, and take items from that queue with several threads. This way thousands of events might happen at once and your upload will still work reliably. Right now you create new thread for each change event, where you immediatly start upload (according to method names) - this will fail under serious load of events (and in cases described above).
No it will not burn you. Even if the ContinueWith is inlined into to the current thread that was running the new Task(() => new DatafeedUploadHandler().. it will get the lock e.g. no dead lock.
The lock statement is using the Monitor class internally, and it is reentrant. e.g. a thread can aquire a lock multiple times if it already got/owns the lock. Multithreading and Locking (Thread-Safe operations)
And the other case where the task.ContinueWith starts before the ProcessModifiedDatafeed finished is like you said. The thread that is running the ContinueWith simply would have to wait to get the lock.
I would really consider to do the task.ContinueWith and the task.Start() outside of the lock if you reviewed it. And it is possible based on your posted code.
You should also take a look at the ConcurrentDictionary in the System.Collections.Concurrent namespace. It would make the code easier and you dont have to manage the locking yourself. You are doing some kind of compare exchange/update here if (this.fileWatcherDictionary.ContainsNonNullKey(eventArgs.FullPath)). e.g. only add if not already in the dictionary. This is one atomic operation. There is no function to do this with a ConcurrentDictionary but there is an AddOrUpdate method. Maybe you can rewrite it by using this method. And based on your code you could safely use the ConcurrentDictionary at least for the runningTaskDictionary
Oh and TaskCreationOptions.LongRunning is literally creating a new thread for every task which is kind of an expensive operation. The windows internal thread pool is intelligent in new windows versions and is adapting dynamically. It will "see" that you are doing lots of IO stuff and will spawn new threads as needed and practical.
Greetings
I have not fully followed the logic of this code but are you aware that task continuations and calls to Wait/Result can be inlined onto the current thread? This can cause reentrancy.
This is very dangerous and has burned many.
Also I don't quite see why you are starting task delayed. This is a code smell. Also why are you wrapping the task creation with try? This can never throw.
This clearly is a partial answer. But the code looks very tangled to me. If it's this hard to audit it you probably should write it differently in the first place.
If I need to cancel some operation on a thread, when should I use Thread.Abort vs Thread.Interrupt. I read the documentation on it but not sure which scneario should i use a particular call between two.
If there is any third way of doing it, please let me knwo about it too with pro and cons.
I would avoid using Thread.Abort at all costs. Its behavior is much safer and predictable since .NET 2.0, but there are still some pretty serious pitfalls with it. Most of the aborts inside managed code can be made safe, but not all of them. For example, I believe there are some subtle problems if an abort request is triggered during the processing of a static constructor. Nevermind, the fact that the out-of-band exception can occur at anytime giving you little control over defining where the safe points for shutdown are located.
There are several acceptable ways to terminate a thread gracefully.
Use Thread.Interrupt
Poll a stopping flag
Use WaitHandle events
Specialized API calls
I discuss these methods in my answer here.
Most suggestions are already done, but here's an example how i would do it:
ManualResetEvent _requestTermination = new ManualResetEvent(false);
Thread _thread;
public void Init()
{
_thread = new Thread(() =>
{
while (!_requestTermination.WaitOne(0))
{
// do something usefull
}
}));
_thread.Start();
}
public void Dispose()
{
_requestTermination.Set();
// you could enter a maximum wait time in the Join(...)
_thread.Join();
}
This way the dispose will wait until the thread has exited.
If you need a delay within the thread, you shouldn't add Thread.Sleep.
Use the WaitOne(delayTime). This way you will never have to wait to terminate it.
I wouldn't use Thread.Abort ever. It causes an exception at an almost arbitrary time.
Be careful with Thread.Interrupt. If you don't build in some waiting or sleeping time the thread won't be interrupted.
Be careful with Thread.Abort. If you catch the ThreadAbortException your thread will terminate right after catch + finally.
(I like to use those methods to send a signal to my thread so that it knows it's terminating time, then clean up and exit.)
So this tells me that I should put a GC.KeepAlive at the end of my code to keep my mutex open (to prevent multiple instances of my app happening due to early GC disposal of my mutex). But should I put the KeepAlive in my finally block or at the end of my try block?
I personally would not use that approach.
The issue is that you need to have something use the mutex after your Application code (in this case, the form) completes, or it will be a candidate for GC post-optimizations.
Since Mutex implements IDisposable, you can just as easily do this:
[STAThread]
static void Main() // args are OK here, of course
{
bool ok;
using(var mutex = new System.Threading.Mutex(true, "YourNameHere", out ok))
{
if (!ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1());
}
}
This will work just as well, since the finally created by the using statement will prevent the mutex from being a GC candidate. I, personally, find this less confusing and cleaner code.
That being said, if you want to follow the approach from that link, just putting KeepAlive anywhere will cause the mutex to not get collected, and prevent the issue. You can put it inside your try or finally block - as long as it's after the main application code "completes". You can also ignore this and just explicitly Dispose() the mutex - as long as you use the mutex some way, it will be fine.
Is there a standard way to close out an application "cleanly" while some WaitHandle objects may be in the state of a current blocking call to WaitOne?
For example, there may be a background thread that is spinning along in a method like this:
while (_request.WaitOne())
{
try
{
_workItem.Invoke();
}
finally
{
OnWorkCompleted();
}
}
I see no obvious way to dispose of this thread without calling Thread.Abort (which from what I understand is discouraged). Calling Close on the _request object (an AutoResetEvent), however, will throw an exception.
Currently, the thread that is running this loop has its IsBackground property set to true, and so the application appears to close properly. However, since WaitHandle implements IDisposable, I'm unsure if this is considered kosher or if that object really ought to be disposed before the app exits.
Is this a bad design? If not, how is this scenario typically dealt with?
Define an additional WaitHandle called _terminate that will signal a request to terminate the loop and then use WaitHandle.WaitAny instead of WaitHandle.WaitOne.
var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
try
{
_workItem.Invoke();
}
finally
{
OnCompleteWork();
}
}
When a thread is blocking (regardless of what it's blocking on) you can call Thread.Interrupt() This will cause the exception ThreadInterruptedException (I believe, it might be a little different) You can handle this exception on the thread itself and do any neccesary clean up.
It's worth noting, that the thread will only throw the ThreadInterruptedException when it is blocking, if it's not blocking it won't be thrown until it next tries to block.
This is the "safe" way of ending threads from what I've read on the subject.
also worth noting: If the object implements both IDisposable and a finializer (which it will if it uses unmanaged resources) the GC will call the finalizer which normally calls dispose. Normally this is non-deterministic. However you can pretty much guarantee they will get called on application exit. Only under very special circumstances they wouldn't. (A .net environment termininating exception such as StackOverflowException is thrown)
Set the IsBackground property to true... it should automatically close the thread when your app ends.
Alternately, you can interrupt the thread by calling Thread.Interrupt and handle the ThreadInterruptedException. Another idea is to call _request.Set() and make the while loop check a volatile flag to determine if the application is closing or if it should continue:
private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
//...
}
// somewhere else in the app
_running = false;
_request.Set();
I think the operating system will clean up after your process has finished. Because your thread is marked as IsBackground the CLR will end the process and all the threads within, so this is not a problem.