#272150 - 13/12/2005 16:19
Locking/sharing files with C#
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Something I am working on at the moment requires multi user updating of files and I'm trying to work out the best way of doing it in C#.
The C# code is in a component being called from some "classic" ASP pages. The component reads files from the web server file system, makes changes to the data and then saves the files again.
The application is multi user (and even without mulitple users there is scope for simultaneous updates to files).
The C# component needs to get some sort of lock on a file when reading it in preparation of a write. If it can't get a lock it needs to wait until it can (and probably give up after a certain period has passed). It can't try to get a lock, fail and then return to the calling code for it to try again later.
All this probably needs to work across processes and definitely across threads.
Performance isn't critical.
I am starting to read up .NET multi-threading and locking. Most of it seems to assume that you are trying to control access to managed objects. In my case however I am controlling access to physical files.
I think the cross-process requirements mean that of the various .NET thread syncronisation schemes Mutex is the only one available to me. I am wondering if I can just use file locking to achieve it though?
The other issue is waiting. Whenever the docs talking about waiting on a lock of some sort they talk about the "thread" blocking until the lock is available. This sounds bad to me when the thread in question could be an ASP worker thread, which could be busy doing other stuff.
Does anyone have any experience in this area?
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272151 - 13/12/2005 16:47
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Replying to my own post... ...using the Mutex class appears to be very easy at least, it amounted to precisely three lines of control to provide the locking I need. I just need to work out what the thread blocking issues are now. I'm not sure that starting a new thread to do the file reading/writing/locking is likely to help as the parent thread would just have to wait for the child to finish before it could do anything useful anyway. Thankfully as I said performance isn't critical, so as long as waiting on a lock doesn't completely stop all ASP activity the Mutex approach should probably work. For anyone interested, the three lines in question were: Code:
Mutex myMutex = new Mutex(false, "OnyxUcf" + fileNameToLock); myMutex.WaitOne(); // do work myMutex.ReleaseMutex();
(though I'll obviously need a try/catch/finally in there at the very least) Still wondering if I can do this sensibly with just file locking instead.
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272152 - 13/12/2005 17:02
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 14/01/2002
Posts: 2858
Loc: Atlanta, GA
|
Quote: I'm not sure that starting a new thread to do the file reading/writing/locking is likely to help as the parent thread would just have to wait for the child to finish before it could do anything useful anyway.
I deleted my post because I figured that couldn't be the right solution- just too complicated and potentially dangerous. However, it would free up your main thread to keep doing whatever background stuff it might need to to function properly. It seems from your post that this really didn't end up being a concern, so your approach should work just fine.
Edited by JeffS (13/12/2005 17:03)
_________________________
-Jeff Rome did not create a great empire by having meetings; they did it by killing all those who opposed them.
|
Top
|
|
|
|
#272153 - 13/12/2005 17:24
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 18/01/2000
Posts: 5683
Loc: London, UK
|
Quote: The C# component needs to get some sort of lock on a file when reading it in preparation of a write.
FileStream.Lock?
_________________________
-- roger
|
Top
|
|
|
|
#272154 - 13/12/2005 18:12
Re: Locking/sharing files with C#
[Re: Roger]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote:
FileStream.Lock?
That would clearly handle the lock, but what about the waiting until it is unlocked part?
With the Mutex I get to call WaitOne() to wait for the Mutex to clear. Using FileStream.Lock I presumably have to then handle the waiting myself?
Do I just try to lock the file, if it fails sleep for a while and then try again (and presumably try this lock, sleep, lock operation a few times)?
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272155 - 13/12/2005 20:28
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 18/01/2000
Posts: 5683
Loc: London, UK
|
Quote: That would clearly handle the lock, but what about the waiting until it is unlocked part?
Interestingly, the documentation is silent on what happens if the file cannot be locked. It implies that it'll block indefinitely.
However, one thing that occurs -- this is a web app, yes? In which case, it'll probably be running in a single ASP.NET helper process, which means that process-afinity locks are no use to you.
On the other hand, since this is a single process, you don't need the mutex, either. You can simply stash an object ("FileArbiter" maybe?) in the HTTP Application state, which you can then get at from the Page methods.
The HttpApplicationState object is available from Page.Application, or HttpContext.Current.Application.
You can then do something like the the following:
In Global.asax, in Application_OnStart:
this.Application["FileArbiter"] = new FileArbiter();
In wherever you need to lock the file:
FileArbiter fileArbiter = this.Application["FileArbiter"]; try { fileArbiter.TryLock(filename, timeout);
// something interesting. } finally { fileArbiter.Unlock(filename); }
...or something like that.
However, there's something in the documentation about "a pool of ... HttpApplication instances." This worries me, because it implies that a web application might not have a single HttpApplication object.
This would be stupid, so I suggest you dig a little more around this area, to see if you can clarify the lifetime/scope of this object.
_________________________
-- roger
|
Top
|
|
|
|
#272156 - 13/12/2005 20:36
Re: Locking/sharing files with C#
[Re: Roger]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote:
However, one thing that occurs -- this is a web app, yes? In which case, it'll probably be running in a single ASP.NET helper process, which means that process-afinity locks are no use to you.
On the other hand, since this is a single process, you don't need the mutex, either. You can simply stash an object ("FileArbiter" maybe?) in the HTTP Application state, which you can then get at from the Page methods.
The HttpApplicationState object is available from Page.Application, or HttpContext.Current.Application.
Unfortunately not, it isn't running within ASP.NET
It is running from "classic" ASP, via a COM interop wrapper. It has to be that way as it is called from a massive exsisting VBScript/Javascript ASP app.
I'll take a look at what I can do with FileStream.Lock tomorrow, otherwise it looks like Mutex might be the best option. Better look to see if there are limits on the number of named Mutexes that you can have as well...
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272157 - 13/12/2005 21:16
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 18/01/2000
Posts: 5683
Loc: London, UK
|
Quote: Better look to see if there are limits on the number of named Mutexes that you can have as well...
AFAIK, there isn't a limit. You can't wait on more than 64 (IIRC) handles at once, however.
Also, if this is COM interop, can't you just use a server EXE? This would be a single process (as long as the ASP pages are all running under the same account).
_________________________
-- roger
|
Top
|
|
|
|
#272159 - 14/12/2005 07:03
Re: Locking/sharing files with C#
[Re: Roger]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote:
FileStream.Lock?
Looking at the docs again it appears that Lock can only be used to lock write access to the file. I need to be able to prevent reads as well.
Ok, definitely taking the Mutex route for now. Thanks for your help Roger and Jeff.
Edited by andy (14/12/2005 07:03)
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272160 - 14/12/2005 12:18
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Well, I have my nice Mutex based resource locking class which seems to work well, even when being hammered by different threads repeatedly locking and unlocking the same Mutex.
There is a problem though, ASP isn't behaving in the multi-threaded nature I expect it to.
If I manually lock the mutex externally from my test app and then load an ASP page that waits for the mutex to be released it blocks all ASP processing for the website until the mutex is released or it times out. I expected other ASP threads to continue processing page requests, even if one was blocked waiting for the lock. This isn't happening, even when an ASP page is requested from a completely separate client machine.
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272161 - 14/12/2005 12:32
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 14/01/2002
Posts: 2858
Loc: Atlanta, GA
|
So blocking the main thread is turning out to be an issue? Would a polling solution work where you set a low timeout on the wait and then come back after giving everything else a chance to run?
_________________________
-Jeff Rome did not create a great empire by having meetings; they did it by killing all those who opposed them.
|
Top
|
|
|
|
#272162 - 14/12/2005 12:36
Re: Locking/sharing files with C#
[Re: JeffS]
|
carpal tunnel
Registered: 18/01/2000
Posts: 5683
Loc: London, UK
|
Quote: after giving everything else a chance to run?
I'm not sure that this is even possible in ASP.
It's possible that ASP is inherently single-threaded.
However, I think maybe Andy's COM interop is not correctly registered as multi-thread capable, and ASP is attempting to work with it from a single thread, causing contention.
_________________________
-- roger
|
Top
|
|
|
|
#272163 - 14/12/2005 12:40
Re: Locking/sharing files with C#
[Re: Roger]
|
carpal tunnel
Registered: 14/01/2002
Posts: 2858
Loc: Atlanta, GA
|
Quote: I'm not sure that this is even possible in ASP.
Yeah, I figured that was likely the case, but I wasn't sure since I've only done a little ASP.
_________________________
-Jeff Rome did not create a great empire by having meetings; they did it by killing all those who opposed them.
|
Top
|
|
|
|
#272164 - 14/12/2005 12:46
Re: Locking/sharing files with C#
[Re: Roger]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote:
However, I think maybe Andy's COM interop is not correctly registered as multi-thread capable, and ASP is attempting to work with it from a single thread, causing contention.
I don't think that is it. The ThreadModel entry is set to "both" in the registry.
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272165 - 14/12/2005 12:56
Re: Locking/sharing files with C#
[Re: JeffS]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote: So blocking the main thread is turning out to be an issue? Would a polling solution work where you set a low timeout on the wait and then come back after giving everything else a chance to run?
At the moment I have a deliberately high wait time of 60 seconds set, to make it easy to analyse the issues. I'll obviously set it much lower than that in production.
I'm going to try replacing my 60 second wait with multiple 100ms waits, to see if that helps.
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272166 - 14/12/2005 13:04
Re: Locking/sharing files with C#
[Re: Roger]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote:
I'm not sure that this is even possible in ASP.
It's possible that ASP is inherently single-threaded.
It is definitely possible for ASP to process more than one ASP page at a time, our app would be awful with multi users if it couldn't (some of our middle tier calls take a second or so to complete).
I spotted however that the number of worker processes for the IIS Application pool was set to one. I increased this to two and that helped a bit.
It helped in that other pages can now sometimes be processed even while one page is waiting on the lock. However it only helps to a certain extent. It appears that ASP page requests are handed out to the worker processes on some some of round-robin scheme. If you lock one worker process and then request another page that second page gets processed (presumably because it is processed by the second unlocked worker process). If you then request the page again it blocks until the lock is released, presumably because it is waiting to be handled by the first locked worker process.
In "the real world" the processing that takes place when the lock is in place will only take a few tens of milliseconds, so I don't think this is actually going to be an issue until something is going seriously wrong already.
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
#272167 - 14/12/2005 13:18
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 14/01/2002
Posts: 2858
Loc: Atlanta, GA
|
Quote: In "the real world" the processing that takes place when the lock is in place will only take a few tens of milliseconds, so I don't think this is actually going to be an issue until something is going seriously wrong already.
In this case, then, it seems to me that if you try to get a lock and timeout after a few seconds, you could just return a failure code and be done with it. If you can't get a lock within a reasonable amount of time then there are other issues to worry about.
_________________________
-Jeff Rome did not create a great empire by having meetings; they did it by killing all those who opposed them.
|
Top
|
|
|
|
#272168 - 14/12/2005 13:19
Re: Locking/sharing files with C#
[Re: andy]
|
carpal tunnel
Registered: 10/06/1999
Posts: 5916
Loc: Wivenhoe, Essex, UK
|
Quote:
I'm going to try replacing my 60 second wait with multiple 100ms waits, to see if that helps.
...and the answer is, no, it doesn't help. Kind of what I expected anyway.
_________________________
Remind me to change my signature to something more interesting someday
|
Top
|
|
|
|
|
|