Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 385
  • Last Modified:

How to use mutex (exclusive synchronization object) to achieve serializing access to a shared resource in C#?

I have an executable which is hosted on a server and can be launched from several client work stations. The exe needs to read and write to two text files that are located in a location shared between all the clients. I need to lock the first text file, and if a lock is obtained successfully the second file needs to be locked for writing and do some processing and unlock the files after processing. So at any time, only one user should be able to access the files.

Also, I need to display some message to the user to try again when the files are locked by another user. It should keep checking if the files are unlocked and keep asking to try again.
Once the files are unlocked, it should show some message to say the files are unlocked  and should be automatically available for the next user to lock and do the processing and unlock after processing.

Did Anybody come across this situation and implemented any of this?
If you could show me some code that would be very helpful. Thank you.
0
ipjyo
Asked:
ipjyo
  • 5
  • 4
6 Solutions
 
Imran Javed ZiaConsultant Software Engineer - .NET ArchitectCommented:
0
 
Todd GerbertIT ConsultantCommented:
I would think you could achieve that just by opening the file with the appropriate FileMode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class Program
{
	static void Main(string[] args)
	{
		Console.WriteLine("Locking TestFile.txt for 30 seconds...");

		try
		{
			using (FileStream fStream = File.Open("TestFile.txt", FileMode.Append, FileAccess.Write, FileShare.None))
			{
				byte[] output = Encoding.ASCII.GetBytes("Hello World!\r\n");
				fStream.Write(output, 0, output.Length);
				System.Threading.Thread.Sleep(30000);
			}
		}
		catch (IOException ex)
		{
			Console.WriteLine("File is locked, try again later.");
			Console.Write("Press any key to exit...");
			Console.ReadKey();
			Environment.Exit(1);
		}

		Console.Write("File is unlocked, press any key to exit...");
		Console.ReadKey();
	}
}

Open in new window

0
 
Todd GerbertIT ConsultantCommented:
Oops, I didn't catch that's basically the same thing IJZ suggested: http:#a35699095 (sorry).
0
NEW Veeam Agent for Microsoft Windows

Backup and recover physical and cloud-based servers and workstations, as well as endpoint devices that belong to remote users. Avoid downtime and data loss quickly and easily for Windows-based physical or public cloud-based workloads!

 
ipjyoAuthor Commented:
Thank you for the responses. It makes sense to use the FileShare.None to achieve this. But I dont understand how to make sure to keep checking if the file is unlocked by the other user or process after showing the message "File is locked, try again later" in catch block. It should not exit but rather keep checking and asking to try again.
Thanks for the help.
0
 
Todd GerbertIT ConsultantCommented:
Do whatever you want in the catch block, you don't have to exit.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class Program
{
	static void Main(string[] args)
	{
		bool fileLocked;

		do
		{
			fileLocked = false;
			try
			{
				Console.WriteLine("Attempting to lock file...");
				using (FileStream fStream = File.Open("TestFile.txt", FileMode.Append, FileAccess.Write, FileShare.None))
				{
					Console.WriteLine("File has been locked.");
					byte[] output = Encoding.ASCII.GetBytes("Hello World!\r\n");
					fStream.Write(output, 0, output.Length);
					System.Threading.Thread.Sleep(30000);
				}
			}
			catch (IOException ex)
			{
				fileLocked = true;
				Console.WriteLine("Could not lock file, waiting for file to unlock...");
			}
		} while (fileLocked);

		Console.Write("File is unlocked, press any key to exit...");
		Console.ReadKey();
	}
}

Open in new window

0
 
ipjyoAuthor Commented:
Thank you very much.

Also, It looks like we don't need to use fStream.Lock and fStream.Unlock methods since FileShare.None is already taking care of that. Correct? I just wanted to understand clearly. Thank you.
0
 
Todd GerbertIT ConsultantCommented:
Kinda six of one,  half dozen of another. I kind of prefer using the "using" block with File.Open(..., FileShare.None) because it guarantees the resources will be freed/unlocked at the end of the "using" block even if an exception is thrown.
0
 
ipjyoAuthor Commented:
Okay. That helped me understood better.

Also, I needed to lock another file after locking the first file. So I included another using block within the first using block. Because I get the value that is stored in the first file and then generate some entries in the second file based on the value from the first file. After updating the second file, I need to write some value back to the first file.

My question is that, If there is an exception how can we know which "using" block is causing the exception? Is it possible to know which file is not available to access?

Thank you.



bool filelocked;
            do
            {
                filelocked = false;
                try
                {

                    using (FileStream JBBSStream = JBBSFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                    {
                        using (FileStream ATEStream = ATEFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                        {
                            try
                            {
                             
				// read the value from JBBS file
				PrevJBBSNumber = GetJBBSNUmber(JBBSStream);

				// Update the ATE file
                                string fileContents = GenerateTransactionsFile();
                                System.IO.File.AppendAllText(ATEFile.FullName, fileContents);

				// write value back to JBBS file
                                UpdateJBBSFile();

                                return true;
                            }
                            catch (Exception x)
                            {
                                string message = string.Format("Error while processing the file. {0}\r\n\r\n{1}", x.Message, x.StackTrace);
                                System.Windows.Forms.MessageBox.Show(message);
                                return false;
                            }
                        }
                    }
                }
                catch (IOException ioex)
                {
                    filelocked = true;
                    MessageBox.Show(ioex.Message);
                    MessageBox.Show("Could not lock the file, waiting for the file to unlock");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("Error when opening the file. {0}", ex.Message));
                }

            } while (filelocked);

Open in new window

0
 
Todd GerbertIT ConsultantCommented:
Just put a try/catch around the using block of interest.

try
{
  using (SomeObject obj = new SomeObject())
  {
    // Some statements that might generate an exception
    try
    {
      using (SomeOtherObject otherObj = new SomeOtherObject())
      {
        // Some other statements that might throw an exception
      }
    }
    catch (Exception ex)
    {
      // SomeOtherObject using block threw an exception
    }
  }
}
catch (Exception ex)
{
  // SomeObject using block threw an exception
}

Open in new window

0
 
ipjyoAuthor Commented:
Thank you for all your help.
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now