Hi,

I have 2 different applications(Application 1 and Application 2) that have a critical area of code where only 1 application can be a time.

The solution I have come up with is to use a lockfile so the application knows about when the other application is in the critical area of code, which seems to work.

The problem:
As seen I use a while loop and Thread.Sleep(1) until it is possible to lock the file.
The problem is this Thread.Sleep(1) which consumes CPU.

However the most important problem here is that Sleep(1), 1 millisecond is to long as I use 100:s of those loops to wait for the same file.

What I wonder is if there is anyway to improve the Sleep/wait time to zero or instantly in any way?

Thank you

            //Application 1
            FileStream stream = null; String lockFile = "C:/lockfile.txt";
            while (true)
            {
                try
                {
                    //Try to Lock file
                    stream = new FileStream(lockFile, FileMode.Open, FileAccess.Read, FileShare.None);
                    break;
                }
                catch
                {
                    //This is heavy for the CPU and will not respond immediately when lockfile is avaliable
                    Thread.Sleep(1); 
                }
            }

            //Do some work

            ///
            ///Critical area where only 1 appliation can be at a time
            ///

            //close the lockfile
            if (stream != null) { stream.Close(); }




            //Application 2
            FileStream stream = null; String lockFile = "C:/lockfile.txt";
            while (true)
            {
                try
                {
                    //Try to Lock file
                    stream = new FileStream(lockFile, FileMode.Open, FileAccess.Read, FileShare.None);
                    break;
                }
                catch
                {
                    //This is heavy for the CPU and will not respond immediately when lockfile is avaliable
                    Thread.Sleep(1); 
                }
            }

            //Do some work

            ///
            ///Critical area where only 1 appliation can be at a time
            ///

            //close the lockfile
            if (stream != null) { stream.Close(); }

Recommended Answers

All 13 Replies

Don't sleep at all.

But that will be a problem for the CPU where 100% of the CPU will be working.
Also in the applications, there are about 100 loops aswell.

Your description of the problem and solution seems dicey. Could you elaborate a bit on what this critical piece of code is so that it's easier to determine what IPC solutions would work best? Right now you basically have a race condition with your locking file, which is a bigger issue than CPU usage, in my opinion.

Thank you for answer,

Yes I will try to describe. I have set a code example of what would be the same scenario of what is happening.

What happens in the critical area of code is reading and writing to a file. This is where the goal is to only have one process to "open, read, modify the file and close the file" at a time.
This because the file must be modified by 1 process at a time, to not get mixed up.

So the code scenario would be the below. The below code should then be used as written in both application 1 and application 2. Where we read a number from a file, increament the number by +1. Write the new value to file and close the file:

Thank you

            //Application 1 and Application 2 use the exact same code as Below

            FileStream stream = null; String lockFile = "C:/lockfile.txt";
            FileStream stream2 = null; StreamReader reader = null; StreamWriter writer = null; String getNumber = ""; String file = "C:/number.txt";

            //Create files, if not exists
            if (File.Exists(lockFile) == false)
            {
                stream2 = new FileStream(lockFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); writer = new StreamWriter(stream2);
                writer.WriteLine(""); writer.Close(); stream2.Close();
            }
            if (File.Exists(file) == false)
            {
                stream2 = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); writer = new StreamWriter(stream2);
                writer.WriteLine("0"); writer.Close(); stream2.Close();
            }

            while (true)
            {
                while (true)
                {
                    try
                    {
                        //Try to Lock file
                        stream = new FileStream(lockFile, FileMode.Open, FileAccess.Read, FileShare.None);
                        break;
                    }
                    catch
                    {
                        //This is heavy for the CPU and will not respond immediately when lockfile is avaliable
                        Thread.Sleep(1);
                    }
                }

                ///
                ///Critical area where only 1 appliation can be at a time
                ///

                //Read number, Add + 1. Write new number to file. Close the file
                stream2 = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); reader = new StreamReader(stream2);
                getNumber = reader.ReadLine(); reader.Close(); stream2.Close();

                getNumber = (Convert.ToInt32(getNumber) + 1).ToString();

                stream2 = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); writer = new StreamWriter(stream2);
                writer.WriteLine(getNumber); writer.Close(); stream2.Close();



                //close the lockfile
                if (stream != null) { stream.Close(); }




                //This sleep is only used for the sake of the example. Don´t mind this sleep.
                Thread.Sleep(1);
            }

Just open the file in exclusive mode. If it fails, do a SpinWait then try again.

Thread.Sleep will not use CPU. It puts the thread to sleep so that it doesn't. What you effectively have there is a spin.

Additionally, the resolution of the timer used for Thread.Sleep cannot guarantee you will recieve a 1ms sleep. A time slice is aproximately 15.6ms so at most, you will wait 15.6ms but very rarely will you achieve your attempted 1ms wait. The only way around this is to use the High Precision Timer. But you're only going to end up increasing CPU usage, not decreasing it.

Thread Sleeping and Spin-Waiting (sorry Momerath ;) ) are bad examples of modern threading. You should use Mutexes and events to synchronise threads. Even lock sections would be better:

static readonly object threadLock = new object();
public WriteString(string data)
{
    lock(threadLock)
    {
        // Open File
        // Write Data
        // Flush Data
        // Close File
    }
}

Only one thread at a time is allowed to pass the lock

Thank you Momerath and Ketsuekiame for answers,

I exercise locks in the application but the problem in this case is that there is a critical code area in 2 different applications. Application 1 and Application 2. (Which actually is a C# application and a Silverlight C# application.)

So I beleive lock(object){} wont be possible to use in this case, in any way?

So if not the "SpinWait" method is a good idéa to use, I might fall back in the question again what could be a good approach or solution?

I have also researched this statement where throwing an exception like I do is very costly in performance. Which perheps is something that should be avoided?
"exceptions are at least 30,000 times slower than return codes"

Have you written both applications?

You can register a Mutex that is accessible at a System level. You can retrieve this Mutex in the application and then perform normal Wait operations on them.

Mutex globalMutex = new Mutex(false, @"//global/FileLockMutex");

Note that there is nothing special about the string I used, it's simply a way I tag that this mutex is used outside this application.

If a Mutex with this ID already exists, it will grab the handle for it, if not, it will create it.

bool handleAcquired = globalMutex.WaitOne(5000);

You can set whatever timeout you want in ms or Timeout.Infinite. This method will return false if the timeout expires and true if the handle was released before then.

As you're running in another process, you should catch the AbandonedMutexException and set the handleAcquired to true. This effectively means that the owner of the mutex abandoned it (possibly by shutting down incorrectly) and now this thread is the owner. Ensure you release the mutex when you're done with it only if you have ownership.

if(handleAcquired) { globalMutex.ReleaseMutex(); }

Yes, I have written both applications so I will be able to design a solution.

"Mutex", did sound like a very good idéa. I didn´t know it was possbile to use a lock across apps.

However I have found a problem. Silverlight which is one of the applications, doesn´t support "Mutex"(It is only supported for windows phone silverlight apps).

Also I found out that "Mutex" is slower than normal lock(object){}, where a "kernel space transition" is needed. This is where the performance will take a great hit, as I use 100 places with the lock and every millisecond counts.

"Mutex utilizes a kernel-level construct, so synchronization will always require at lesat a user space-kernel space transition"

I could hopfully redesign the code where I use those locks to be as small as possible, to be able to use a "SpinWait" solution in combination with a lockfile?

But best might be to see if there could be any other solution?

If you need to lock, especially for IO, the performance of the Mutex operations is insignificant (approximately 50 nanoseconds). IO will take vastly longer than grabbing a Mutex. Even spin waiting, you're making your application wait. Not going to be high performance ;)
I think you're misunderstanding what thread synchronisation does.

If you have 100 threads (bad idea in the first place but lets roll with it) if you enter a critical section and all 100 of those threads want to enter at the same time, then only 1 thread is allowed to execute and the other 99 have to stop executing and wait until that thread has finished. Then one more thread is allowed, then one more and so on. The performance of grabbing the lock is nothing compared to waiting for the owning thread to complete. Additionally, you would have to call this hundreds of thousands of times before you see any significant slow-down in terms of maybe tens of milliseconds. To put this into perspective, you would need to grab the mutex one hundred million times for it to cost five seconds over the course of your application executing. The time spent waiting for IO could easily equal this in a single call depending on what you're writing.

You say that one of these applications is a silverlight application. Are you tring to write to the local client's file system using a browser plugin whilst an application on the same machine writes to the same file? If this is the case you may wish to reconsider your design as it seems to be wrong at a fundamental level. For a start, a silverlight browser plugin should not be writing to the general file system, in fact, I believe this represents a security risk.

Without knowing at a higher level what you want to do though I can't assist in your design, but I believe there is a much simpler solution than what you proposed.

The Mutex sounds very good when you have explained it. As it seems, It is very bad that Silverlight doesn´t have this Mutex. Only for windows phone applications on silverlight.

The Silverlight application I develop is a Out Of Browser application so it has access to the local file system with all IO etc. However some things are slimmed down in the classes like this Mutex.
It will be impossible to redesign the silverlight application because it is to much code in there.

The silverlight application was the first I started with. Long way in the development, I was needed to make COM calls, which Silverlight didn´t support and still doesn´t. So I had to create a Form application to be able to use those functions.

This is where those applications needs this critical sync communication, in some areas.
I have a TCP solution between the application which works. I am actually now moving 4000 lines from the silverlight application to the Form application where I will be able to remove the locks completetly, using a new design where only the Form application will do this work. So I will send info over TCP to the Form application etc.. However much to change.

Still in many other areas in the applications, there would be many code places that would be very happy about that Mutex :/

I'm still not convinced you need Silverlight, but I'll leave you to it as that isn't my call and i'm slightly biased against it ;)

I hope you manage to complete your project. Feel free to come back if you need any more help on threading.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.