I've got a web application that controls which web applications get served traffic from our load balancer. The web application runs on each individual server.
It keeps track of the "in or out" state for each application in an object in the ASP.NET application state, and the object is serialized to a file on the disk whenever the state is changed. The state is deserialized from the file when the web application starts.
While the site itself only gets a couple requests a second tops, and the file it rarely accessed, I've found that it was extremely easy for some reason to get collisions while attempting to read from or write to the file. This mechanism needs to be extremely reliable, because we have an automated system that regularly does rolling deployments to the server.
Before anyone makes any comments questioning the prudence of any of the above, allow me to simply say that explaining the reasoning behind it would make this post much longer than it already is, so I'd like to avoid moving mountains.
That said, the code that I use to control access to the file looks like this:
internal static Mutex _lock = null;
/// <summary>Executes the specified <see cref="Func{FileStream, Object}" /> delegate on
/// the filesystem copy of the <see cref="ServerState" />.
/// The work done on the file is wrapped in a lock statement to ensure there are no
/// locking collisions caused by attempting to save and load the file simultaneously
/// from separate requests.
/// </summary>
/// <param name="action">The logic to be executed on the
/// <see cref="ServerState" /> file.</param>
/// <returns>An object containing any result data returned by <param name="func" />.
///</returns>
private static Boolean InvokeOnFile(Func<FileStream, Object> func, out Object result)
{
var l = new Logger();
if (ServerState._lock.WaitOne(1500, false))
{
l.LogInformation( "Got lock to read/write file-based server state."
, (Int32)VipEvent.GotStateLock);
var fileStream = File.Open( ServerState.PATH, FileMode.OpenOrCreate
, FileAccess.ReadWrite, FileShare.None);
result = func.Invoke(fileStream);
fileStream.Close();
fileStream.Dispose();
fileStream = null;
ServerState._lock.ReleaseMutex();
l.LogInformation( "Released state file lock."
, (Int32)VipEvent.ReleasedStateLock);
return true;
}
else
{
l.LogWarning( "Could not get a lock to access the file-based server state."
, (Int32)VipEvent.CouldNotGetStateLock);
result = null;
return false;
}
}
This usually works, but occasionally I cannot get access to the mutex (I see the "Could not get a lock" event in the log). I cannot reproduce this locally - it only happens on my production servers (Win Server 2k3/IIS 6). If I remove the timeout, the application hangs indefinitely (race condition??), including on subsequent requests.
When I do get the errors, looking at the event log tells me that the mutex lock was achieved and released by the previous request before the error was logged.
The mutex is instantiated in the Application_Start event. I get the same results when it is instantiated statically in the declaration.
Excuses, excuses: threading/locking is not my forté, as I generally don't have to worry about it.
Any suggestions as to why it randomly would fail to get a signal?
Update:
I've added proper error handling (how embarrassing!), but I am still getting the same errors - and for the record, unhandled exceptions were never the problem.
Only one process would ever be accessing the file - I don't use a web garden for this application's web pool, and no other applications use the file. The only exception I can think of would be when the app pool recycles, and the old WP is still open when the new one is created - but I can tell from watching the task manager that the issue occurs while there is only one worker process.
#mmr: How is using Monitor any different from using a Mutex? Based on the MSDN documentation, it looks like it is effectively doing the same thing - if and I can't get the lock with my Mutex, it does fail gracefully by just returning false.
Another thing to note: The issues I'm having seem to be completely random - if it fails on one request, it might work fine on the next. There doesn't seem to be a pattern, either (certainly no every other, at least).
Update 2:
This lock is not used for any other call. The only time _lock is referenced outside the InvokeOnFile method is when it is instantiated.
The Func that is invoked is either reading from the file and deserializing into an object, or serializing an object and writing it to the file. Neither operation is done on a separate thread.
ServerState.PATH is a static readonly field, which I don't expect would cause any concurrency problems.
I'd also like to re-iterate my earlier point that I cannot reproduce this locally (in Cassini).
Lessons learned:
Use proper error handling (duh!)
Use the right tool for the job (and have a basic understanding of what/how that tool does). As sambo points out, using a Mutex apparently has a lot of overhead, which was causing issues in my application, whereas Monitor is designed specifically for .NET.
You should only be using Mutexes if you need cross-process synchronization.
Although a mutex can be used for
intra-process thread synchronization,
using Monitor is generally preferred,
because monitors were designed
specifically for the .NET Framework
and therefore make better use of
resources. In contrast, the Mutex
class is a wrapper to a Win32
construct. While it is more powerful
than a monitor, a mutex requires
interop transitions that are more
computationally expensive than those
required by the Monitor class.
If you need to support inter-process locking you need a Global mutex.
The pattern being used is incredibly fragile, there is no exception handling and you are not ensuring that your Mutex is released. That is really risky code and most likely the reason you see these hangs when there is no timeout.
Also, if your file operation ever takes longer than 1.5 seconds then there is a chance concurrent Mutexes will not be able to grab it. I would recommend getting the locking right and avoiding the timeout.
I think its best to re-write this to use a lock. Also, it looks like you are calling out to another method, if this take forever, the lock will be held forever. That's pretty risky.
This is both shorter and much safer:
// if you want timeout support use
// try{var success=Monitor.TryEnter(m_syncObj, 2000);}
// finally{Monitor.Exit(m_syncObj)}
lock(m_syncObj)
{
l.LogInformation( "Got lock to read/write file-based server state."
, (Int32)VipEvent.GotStateLock);
using (var fileStream = File.Open( ServerState.PATH, FileMode.OpenOrCreate
, FileAccess.ReadWrite, FileShare.None))
{
// the line below is risky, what will happen if the call to invoke
// never returns?
result = func.Invoke(fileStream);
}
}
l.LogInformation("Released state file lock.", (Int32)VipEvent.ReleasedStateLock);
return true;
// note exceptions may leak out of this method. either handle them here.
// or in the calling method.
// For example the file access may fail of func.Invoke may fail
If some of the file operations fail, the lock will not be released. Most probably that is the case. Put the file operations in try/catch block, and release the lock in the finally block.
Anyway, if you read the file in your Global.asax Application_Start method, this will ensure that noone else is working on it (you said that the file is read on application start, right?). To avoid collisions on application pool restaring, etc., you just can try to read the file (assuming that the write operation takes an exclusive lock), and then wait 1 second and retry if exception is thrown.
Now, you have the problem of synchronizing the writes. Whatever method decides to change the file should take care to not invoke a write operation if another one is in progress with simple lock statement.
I see a couple of potential issues here.
Edit for Update 2: If the function is a simple serialize/deserialize combination, I'd separate the two out into two different functions, one into a 'serialize' function, and one into a 'deserialize' function. They really are two different tasks. You can then have different, lock-specific tasks. Invoke is nifty, but I've gotten into lots of trouble myself going for 'nifty' over 'working'.
1) Is your LogInformation function locking? Because you call it inside the mutex first, and then once you release the mutex. So if there's a lock to write to the log file/structure, then you can end up with your race condition there. To avoid that, put the log inside the lock.
2) Check out using the Monitor class, which I know works in C# and I'd assume works in ASP.NET. For that, you can just simply try to get the lock, and fail gracefully otherwise. One way to use this is to just keep trying to get the lock. (Edit for why: see here; basically, a mutex is across processes, the Monitor is in just one process, but was designed for .NET and so is preferred. No other real explanation is given by the docs.)
3) What happens if the filestream opening fails, because someone else has the lock? That would throw an exception, and that could cause this code to behave badly (ie, the lock is still held by the thread that has the exception, and another thread can get at it).
4) What about the func itself? Does that start another thread, or is it entirely within the one thread? What about accessing ServerState.PATH?
5) What other functions can access ServerState._lock? I prefer to have each function that requires a lock get its own lock, to avoid race/deadlock conditions. If you have many many threads, and each of them try to lock on the same object but for totally different tasks, then you could end up with deadlocks and races without any really easily understandable reason. I've changed to code to reflect that idea, rather than using some global lock. (I realize other people suggest a global lock; I really don't like that idea, because of the possibility of other things grabbing it for some task that is not this task).
Object MyLock = new Object();
private static Boolean InvokeOnFile(Func<FileStream, Object> func, out Object result)
{
var l = null;
var filestream = null;
Boolean success = false;
if (Monitor.TryEnter(MyLock, 1500))
try {
l = new Logger();
l.LogInformation("Got lock to read/write file-based server state.", (Int32)VipEvent.GotStateLock);
using (fileStream = File.Open(ServerState.PATH, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)){
result = func.Invoke(fileStream);
} //'using' means avoiding the dispose/close requirements
success = true;
}
catch {//your filestream access failed
l.LogInformation("File access failed.", (Int32)VipEvent.ReleasedStateLock);
} finally {
l.LogInformation("About to released state file lock.", (Int32)VipEvent.ReleasedStateLock);
Monitor.Exit(MyLock);//gets you out of the lock you've got
}
} else {
result = null;
//l.LogWarning("Could not get a lock to access the file-based server state.", (Int32)VipEvent.CouldNotGetStateLock);//if the lock doesn't show in the log, then it wasn't gotten; again, if your logger is locking, then you could have some issues here
}
return Success;
}
Related
I have a txt file ABC.txt which will be read and wrote by multi processes. So when one process is reading from or writing to file ABC.txt, file ABC.txt must be locked so that any other processes can not reading from or writing to it. I know the enum System.IO.FileShare may be the right way to handle this problem. But I used another way which I'm not sure if it is right. The following is my solution.
I added another file Lock.txt to the folder. Before I can read from or write to file ABC.txt, I must have the capability to read from file Lock.txt. And after I have read from or written to file ABC.txt, I have to release that capability. The following is the code.
#region Enter the lock
FileStream lockFileStream = null;
bool lockEntered = false;
while (lockEntered == false)
{
try
{
lockFileStream = File.Open("Lock.txt", FileMode.Open, FileAccess.Read, FileShare.None);
lockEntered = true;
}
catch (Exception)
{
Thread.Sleep(500);
}
}
#endregion
#region Do the work
// Read from or write to File ABC.txt
// Read from or write to other files
#endregion
#region Release the lock
try
{
if (lockFileStream != null)
{
lockFileStream.Dispose();
}
}
catch
{
}
#endregion
On my computer, it seems that this solution works well, but I still can not make sure if it is appropriate..
Edit: Multi processes, not multi threads in the same process.
C#'s named EventWaitHandle is the way to go here. Create an instance of wait handle in every process which wants to use that file and give it a name which is shared by all such processes.
EventWaitHandle waitHandle = new EventWaitHandle(true, EventResetMode.AutoReset, "SHARED_BY_ALL_PROCESSES");
Then when accessing the file wait on waitHandle and when finished processing file, set it so the next process in the queue may access it.
waitHandle.WaitOne();
/* process file*/
waitHandle.Set();
When you name an event wait handle then that name is shared across all processes in the operating system. Therefore in order to avoid possibility of collisions, use a guid for name ("SHARED_BY_ALL_PROCESSES" above).
A mutex in C# may be shared across multiple processes. Here is an example for multiple processes writing to a single file:
using (var mutex = new Mutex(false, "Strand www.jakemdrew.com"))
{
mutex.WaitOne();
File.AppendAllText(outputFilePath,theFileText);
mutex.ReleaseMutex();
}
You need to make sure that the mutex is given a unique name that will be shared across the entire system.
Additional reading here:
http://www.albahari.com/threading/part2.aspx#_Mutex
Your solution is error prone. You've basically implemented double-checked locking (http://en.wikipedia.org/wiki/Double-checked_locking) which can be very unsafe.
A better solution would be to either introduce thread isolation, whereby only one thread ever accesses the file and does so by reading from a queue upon which requests to read or write are placed by other threads (and of course the queue is protected by mutually exclusive access by threads) or where the threads synchronize themselves either by synchronization devices (lock sections, mutices, whatever) or by using some other file access logic (for example, System.IO.FileShare came up in a few reponses here.)
If it was me, I would install something like SQL Server Compact Edition for reading/writing this data.
However, if you want to be able to lock access to a resource that is shared between multiple processes, you need to use a Mutex or a Semaphore.
The Mutex class is a .Net wrapper around an OS Level locking mechanism.
Overview of Synchronization Primitives
I'm taking over a C# project, and when testing it out I'm getting errors. The error is that the log file cannot be written to because it is in use by another process. Here's the code:
public void WriteToLog(string msg)
{
if (!_LogExists)
{
this.VerifyOrCreateLogFile(); // Creates log file if it does not already exist.
}
// do the actual writing on its own thread so execution control can immediately return to the calling routine.
Thread t = new Thread(new ParameterizedThreadStart(WriteToLog));
t.Start((object)msg);
}
private void WriteToLog(object msg)
{
lock (_LogLock)
{
string message = msg as string;
using (StreamWriter sw = File.AppendText(LogFile))
{
sw.Write(message);
sw.Close();
}
}
}
_LogLock is defined as a class variable:
private object _LogLock = 0;
Based on my research and the fact that this has been working fine in a production system for a few years now, I don't know what the problem could be. The lock should prevent another thread from attempting to write to the log file.
The changes I've made that need to be tested are a lot more log usage. We're basically adding a debug mode to save much more info to the log than used to be saved.
Thanks for any help!
EDIT:
Thanks for the quick answers! The code for VerifyOrCreateLogFile() does use the _LogLock, so that shouldn't be an issue. It does do some writing to the log before it errors out, so it gets past creating the file just fine.
What seems to be the problem is that previously only one class created an instance of the log class, and now I've added instances to other classes. It makes sense that this would create problems. Changing the _LogLock field to be static fixes the issue.
Thanks again!
The lock should prevent another thread from attempting to write to the log file.
This is only true if you're using a single instance of this class.
If each (or even some) of the log requests use a separate instance, then the lock will not protect you.
You can easily "correct" this by making the _LogLock field static:
private static object _LogLock = 0;
This way, all instances will share the same lock.
I see 2 problems with the code:
Lock must be the same among all "users" of ths Log class, easiest solution is to make either _LogLock or the complete class static
VerifyOrCreateLogFile could pose a problem if 2 or more parallel threads call WriteToLog when _LogExists is false...
One possibility is that the OS isn't releasing the file lock quickly enough before you exit the lock in WriteToLog and another thread that was blocked waiting for the lock tried to open it before the OS finished releasing the file lock. Yes, it can happen. You either need to sleep for a little before trying to open the file, centralize the writing to the log to a dedicated object (so that he and only he has access to this file and you don't have to worry about file lock contentions).
Another possibility is that you need to lock around
if (!_LogExists) {
this.VerifyOrCreateLogFile(); // Creates log file if it does not already exist.
}
The third possibility is that you have multiple instances of whatever class is housing these methods. The lock object won't be shared across instances (make it static to solve this).
At the end of the day, unless you're an expert in writing safe multi-threaded code, just let someone else worry about this stuff for you. Use a framework that handles these issues for you (log4net?).
you can do the code executable by simply
removing sw.Close(); from your code ...
do it....
it will work fine.....
I have the same BackgroundWorker code piece in two simultaneously running applications. Will this code avoid the problem of same resource getting access by two processes and run smoothly?
void bw_DoWork(object sender, DoWorkEventArgs e)
{
bool flag = false;
System.Threading.Thread.Sleep(1000);
while (flag.Equals(false))
{
string dir = #"C:\ProgramData\Msgs";
try
{
if (Directory.GetFiles(smsdir).Length > 0)
{
flag = true;
}
}
catch (Exception exc)
{
Logger.Log("Dir Access Exception: " + exc.Message);
System.Threading.Thread.Sleep(10);
}
}
On one level, depending on what you're doing, there's nothing wrong with having multiple applications accessing the same directory or file. If it's just read access, then by all means, both can access it at once.
If you've got identical code in multiple applications, then a Boolean isn't going to cut it for synchronization, no matter what you do: Each application has its own copy of the Boolean, and cannot modify the other.
For cross application synhronization, I'd use the Mutex class. There's a constructor that takes a string parameter, specifying the name of the Mutex. Mutex names are unique across all of Windows, not just your application. You can do Mutex m = new Mutex(false, "MySpecialMutex"); in two different applications, and each object will be referring to the same thing.
No, it won't solve the issue because setting the boolean's value and checking it is not an atomic function and is thus not thread safe. You have to use either a Mutex or a Monitor object.
Check this link for more info: Monitor vs Mutex in c#
No, it will not -- at least, the code you have pasted will not accomplish any sort of meaningful process synchronization.
If you want a more detailed and helpful answer, you are going to need to be more specific about what you are doing.
You must come up with some kind of cross-process synchronization scheme - any locking mechanism you use in that code is irrelevant if you're trying to prevent collisions between two processes as opposed to two threads running on the same process.
A good way to do locking across processes like this is to use a file. First process in creates a file and opens it with exclusive access, and then deletes it when its done. The second process in will either see that the file exists and have to wait till it doesn't or it will fail when attempting to open the file exclusively.
no, 'flag' is local to the scope of the method, which is local to the scope of the thread. In other words, it will also equal false.
This is what the lock function is for. Use it like this
In your class, declare a private object called gothread.
in your method write it like this
lock(gothread)
{
// put your code in here, one thread will not be able to enter when another thread is already
// in here
}
Can anyone point me to a good working solution to the following problem?
The application I'm working on needs to communicate over TCP to software running on another system. Some of the requests I send to that system can take a long time to complete (up to 15sec).
In my application I have a number of threads, including the main UI thread, which can access the service which communicates with the remote system. There is only a single instance of the service which is accessed by all threads.
I need to only allow a single request to be processed at a time, i.e. it needs to be serialized, otherwise bad things happen with the TCP comms.
Attempted Solutions so far
Initially I tried using lock() with a static object to protect each 'command' method, as follows:
lock (_cmdLock)
{
SetPosition(position);
}
However I found that sometimes it wouldn't release the lock, even though there are timeouts on the remote system and on the TCP comms. Additionally, if two calls came in from the same thread (e.g. a user double clicked a button) then it would get past the lock - after reading up about locking again I know that the same thread won't wait for the lock.
I then tried to use AutoResetEvents to only allow a single call through at a time. But without the locking it wouldn't work with multiple threads. The following is the code I used to send a command (from the calling thread) and process a command request (running in the background on its own thread)
private static AutoResetEvent _cmdProcessorReadyEvent = new AutoResetEvent(false);
private static AutoResetEvent _resultAvailableEvent = new AutoResetEvent(false);
private static AutoResetEvent _sendCommandEvent = new AutoResetEvent(false);
// This method is called to send each command and can run on different threads
private bool SendCommand(Command cmd)
{
// Wait for processor thread to become ready for next cmd
if (_cmdProcessorReadyEvent.WaitOne(_timeoutSec + 500))
{
lock (_sendCmdLock)
{
_currentCommand = cmd;
}
// Tell the processor thread that there is a command present
_sendCommandEvent.Set();
// Wait for a result from the processor thread
if (!_resultAvailableEvent.WaitOne(_timeoutSec + 500))
_lastCommandResult.Timeout = true;
}
return _lastCommandResult.Success;
}
// This method runs in a background thread while the app is running
private void ProcessCommand()
{
try
{
do
{
// Indicate that we are ready to process another commnad
_cmdProcessorReadyEvent.Set();
_sendCommandEvent.WaitOne();
lock (_sendCmdLock)
{
_lastCommandResult = new BaseResponse(false, false, "No Command");
RunCOMCommand(_currentCommand);
}
_resultAvailableEvent.Set();
} while (_processCommands);
}
catch (Exception ex)
{
_lastCommandResult.Success = false;
_lastCommandResult.Timeout = false;
_lastCommandResult.LastError = ex.Message;
}
}
I haven't tried implementing a queue of command requests as the calling code expects everything to be synchronous - i.e. the previous command must have completed before I sent the next one.
Additional Background
The software running on the remote system is a 3rd party product and I don't have access to it, it is used to control a laser marking machine with an integrated XY table.
I'm actually using a legacy VB6 DLL to communicate with the laser as it has all the code for formatting commands and processing the responses. This VB6 DLL uses a WinSock control for the comms.
I'm not sure why a queueing solution wouldn't work.
Why not put each request, plus details for a callback with result, on a queue ? Your application would queue these requests, and the module interfacing to your 3rd party system can take each queue item in turn, process, and return the result.
I think it's a cleaner separation of concerns between modules rather than implementing locking around request dispatch etc. Your requestor is largely oblivious of the serialisation constraints, and the 3rd-party interfacing module can look after serialisation, managing timeouts and other errors etc.
Edit: In the Java world we have BlockingQueues which are synchronised for consumers/publishers and make this sort of thing quite easy. I'm not sure if you have the same in the C# world. A quick search suggests not, but there's source code floating around for this sort of thing (if anyone in the C# world can shed some light that would be appreciated)
I open a FileStream with FileMode.Open and FileAccess.Read. Shortly after that I call a function to handle the file's contents. I use Invoke to make the call because the call comes from a Thread and the function has to put the results on a Form. The function accepts any kind of Stream (I call it with MemoryStreams too without a problem) and uses XmlTextReader to read the XML in the FileStream, but on rare occasions for unknown reasons even the first Read() throws an ObjectDisposedException and the stream's CanRead property returns false if the stream was already closed.
In the Thread the FileStream is a local using variable, so I don't think another threads should be able to close it, and I don't close it until the Invoke returned. There are no Exceptions thrown so the file is definetly there (since there is no FileNotFoundException) and should be accessed properly (since there is no UnauthorizedAccessException and IOException).
How could my FileStream still look closed sometimes just after opened?
(It might matter that I'm running my code on a Windows CE 5 device with Compact Framework 3.5 and I wasn't able to reproduce the same behaviour on my desktop PC with XP yet.)
EDIT:
I know, that this Invoke is ugly but that alone can't be a reason to fail, can it? (And, in most of the cases it doesn't fail at all.)
//the code in the thread
//...
using (FileStream fs = File.Open(assemblyPath + "\\white.xml", FileMode.Open, FileAccess.Read))
{
mainForm.Instance.Invoke(new DataHandler(mainForm.Instance.handleData), new object[] { fs });
}
//...
//and the handler
public void handleData(Stream stream)
{
infoPanel.SuspendLayout();
try
{
using (XmlTextReader xml = new XmlTextReader(stream))
{
//it doesn't matter what is here
}
}
catch{}
}
There's one reason I can think of: the worker thread got aborted. This will run the finally block generated by the using statement and close the file. How it could be aborted is a secondary question. Is the thread's IsBackground property set to true? Is the program bombing on an unhandled exception elsewhere and shutting down? Just guesses of course.
Sure, this is expected behavior. You call Invoke, which marshals the call to another thread. The calling thread then continues to run and the using block exits, calling Dispose on the stream. This Dispose is happening before you are done (and maybe before you start) using the stream in the UI thread. The exact timing of these actions is going to depend on processor load and some other factors, but it's certainly unsafe.
Either don't put the stream in a using block or better yet have the thread do the read and pass the results to the UI via Invoke.
EDIT
As Hans points out in the comment, the above explanation should be for a BeginInvoke call, which underneath calls PostMessage. Invoke, on the other hand, uses SendMessage. Both propbably uses some WM_COPYDATA shenanigans (I've not looked to see) to marshal the data.
The Invoke call should be executing the entire handler you have posted, though the behavior you see indicates otherwise. From the code you posted there's no real way for us to determine what is closing the stream.
I would still refactor what you've done here because right now you're tying up both the UI and worker threads with the reader operation. I'd do the read work in the worker thread and then pass the results to the UI. This would decrease the odds of the reader work causing UI choppiness and would eliminate the possibility of the stream getting closed while you're reading from it.
I saw the same issue on some embedded board (ARM) I'm working on. Then I created a little test.
The following code (not involving any Threads!) crashes:
using (var w = new StreamWriter(File.Create("file.txt"), System.Text.Encoding.UTF8))
{
for (int i = 0; i < 1000; i++)
{
w.WriteLine("Test");
}
}
This code however does not crash:
using (var w = File.CreateText("file.txt"))
{
for (int i = 0; i < 1000; i++)
{
w.WriteLine("Test");
}
}
So, my guess can only be that the underlying native code treats text files differently than when you open the file using File.Create(). Both files are then written in UTF-8, so there is no difference about the encoding.
BTW: sorry I'm one year late on the answer, but I hope it'll help somebody