I'm writing an ASP.NET web application using C# that may read and write a text file from the IIS server (using System.IO.FileStream
) and I'm wondering how do I implement a global lock on this operation?
Asked
Active
Viewed 5,162 times
5 Answers
4
For global lock you need mutex
// The key can be part of the file name -
// be careful not all characters are valid
var mut = new Mutex(true, key);
try
{
// Wait until it is safe to enter.
mut.WaitOne();
// here you manipulate your file
}
finally
{
// Release the Mutex.
mut.ReleaseMutex();
}

Aristos
- 66,005
- 16
- 114
- 150
-
Thanks. A follow-up question. Do I have to make the mutex name in your 'key' variable as `Global\key` for it to be read on a global scale? – c00000fd Mar 03 '13 at 00:47
-
@c00000fd The key, what ever the name is, is global for the computer. – Aristos Mar 03 '13 at 00:49
-
OK. I'm basing it on WinAPI named mutexes (which I believe this one is "on the inside"). Read description for the `lpName` parameter: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682411(v=vs.85).aspx – c00000fd Mar 03 '13 at 00:59
-
@c00000fd I do not understand you. Can you tell direct your point? – Aristos Mar 03 '13 at 01:01
-
@c00000fd I use it on my program with out set any Global\ at the front and is lock globally. Now I do not know how more global can be and what is this global in front is mean/used. – Aristos Mar 03 '13 at 01:07
-
It the unmanaged world the `Global\ ` prefix on the name will make that synchronization object global vs. local (`global` meaning that a process running in one session will see this object from another session.) I was thinking to use it because I'm not sure from how many sessions my ASP.NET web app may be running on the IIS? It'd be nice if someone could confirm or deny it? – c00000fd Mar 03 '13 at 01:13
-
@c00000fd I do not know to answer what this global means and how is used. I use the mutex on my program that is web garden with 5 pools, many threads each pool, with out set any global there, and the mutex works as global. The mutex is global for the computer. – Aristos Mar 03 '13 at 01:16
-
1Check this one: http://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c – c00000fd Mar 03 '13 at 01:19
-
@c00000fd Yes, ok I will check it with details on my program. – Aristos Mar 03 '13 at 01:22
-
Aren't named mutex system-wide? If yes it's quite expensive. And is not necessary for operations inside a single process. Isn't it? – abatishchev Mar 03 '13 at 02:09
-
@abatishchev: Are you sure that your web app will run in a single process? – c00000fd Mar 03 '13 at 06:50
-
@c00000fd: One application pool - one process, usually. [You can change that](http://stackoverflow.com/questions/2659571/how-does-application-pool-work-in-iis) however it's not recommended or better to say not used. – abatishchev Mar 03 '13 at 06:53
-
@abatishchev: So if my web app is opened through several web browsers connecting from different IPs, it will run in a single process, correct? – c00000fd Mar 03 '13 at 07:03
-
@c00000fd: On the server, yes. You can get corresponding PID (process id) [easily](http://stackoverflow.com/questions/748927/iis-application-pool-pid). – abatishchev Mar 03 '13 at 07:07
-
You will get permissions issues if you're using this code in multiple Application Pools. In that case, http://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c is a better solution -- the errors will look something like: ("Access to the path 'myMutexName' is denied.") – GlennG Jan 30 '15 at 10:31
-
@GlennG Thank you for the note, this is an idea, not a fully class that can handle all the cases. Now about the security issues, up to now I didnt have any issue, but thank you for the note. Please also note, here we have asp.net pool, runs under the same account, we do not have multiple accounts) – Aristos Jan 30 '15 at 10:40
1
The easiest solution would be to create a new object in the Cache or Application object, preferably in the Application_Startup within the global.asax file. Such as:
Cache["myLocker"] = new object();
Then you can use the standard "lock" syntax.
lock(Cache["myLocker"])
{
// do file access here...
}

Tim P.
- 2,903
- 24
- 26
-
`Application` is first thing coming to mind. But I was told once and I like this idea that this class was provided for Classic ASP compatibility and you don't need it actually because you can use static classes instead which are much faster. – abatishchev Mar 03 '13 at 02:17
1
From what @Aristos suggested and from this post, I came up with this class:
using System.Threading;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Runtime.InteropServices; //GuidAttribute
using System.Reflection; //Assembly
namespace ITXClimateSaverWebApp
{
public class GlobalNamedLock
{
private Mutex mtx;
public GlobalNamedLock(string strLockName)
{
//Name must be provided!
if(string.IsNullOrWhiteSpace(strLockName))
{
//Use default name
strLockName = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
}
//Create security permissions for everyone
//It is needed in case the mutex is used by a process with
//different set of privileges than the one that created it
//Setting it will avoid access_denied errors.
MutexSecurity mSec = new MutexSecurity();
mSec.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
MutexRights.FullControl, AccessControlType.Allow));
//Create the global mutex
bool bCreatedNew;
mtx = new Mutex(false, @"Global\" + strLockName, out bCreatedNew, mSec);
}
public bool enterCRITICAL_SECTION()
{
//Enter critical section
//INFO: May throw an exception!
//RETURN:
// = 'true' if successfully entered
// = 'false' if failed (DO NOT continue!)
//Wait
return mtx.WaitOne();
}
public void leaveCRITICAL_SECTION()
{
//Leave critical section
//INFO: May throw an exception!
//Release it
mtx.ReleaseMutex();
}
}
}
and then the way to call it for a global lock:
try
{
GlobalNamedLock gl = new GlobalNamedLock("MyLockName");
try
{
if (gl.enterCRITICAL_SECTION())
{
//Use the global resource now
}
}
finally
{
gl.leaveCRITICAL_SECTION();
}
}
catch (Exception ex)
{
//Failed -- log it
}
So this seems to do the job. What do you think?
-
I'd suggest to use other names rather than `enterCRITICAL_SECTION` and `leaveCRITICAL_SECTION`. They are totally unacceptable in any programming language I even could imagine. – abatishchev Mar 03 '13 at 02:15
-
A lot of code to main that is more complex than the built-in "lock" keyword with C#. – Tim P. Mar 05 '13 at 23:32
-
-
@c00000fd: You're re-writing the exact same stuff that the "lock" keyword does. – Tim P. Mar 07 '13 at 15:36
-
-
-
@CyanLite: What if I want to have two or more differentiated locks. How do I do that? With a named mutex you can obviously do it with its name. – c00000fd Mar 12 '13 at 04:51
0
Why don't just use global sync root object?
internal static class Lock
{
public static object SyncRoot = new object{};
}
Usage:
lock (Lock.SyncRoot)
{
}

abatishchev
- 98,240
- 88
- 296
- 433
-
Is it because this static lock doesn't really work with multiple worker processes? – Shiroy Apr 18 '17 at 22:57
-
This answer is wrong actually, and wont work in cases with multiple worker processes. – Ahmad Aug 18 '19 at 20:48
-
@Ahmad: the question mentions nothing about "multiple worker processes", neither all other answers, basically. So what are you talking about exactly? – abatishchev Aug 19 '19 at 03:46
-
@abatishchev It is talking about a global lock, and the way you provide will not do that in some cases that will not be rare. That's my point. – Ahmad Aug 20 '19 at 06:07
-
@Ahmad: which of the answers above *would work* with multiple worker processes? – abatishchev Aug 20 '19 at 06:26
-
-
@Ahmad: Fair enough. However, the question itself mentions nothing of that in the initial requirements. – abatishchev Aug 21 '19 at 18:56
0
Named mutexes are systems objects. Unlike lock keywords, they work even across process boundaries. Lock is only useful in the context of synchronizing threads in same process.