Devign Blog

Technology and Self-improvement

Locking shared objects in .NET

clock October 16, 2008 23:56 by author devignadmin

If you have a shared (static) object in a class, and multiple threads handle this object, potentially at the same time, you might run into some problems. For example, let's say you have a shared collection of items. Now you might have a method to add an item, a method to remove an item, and a method to retrieve an item. But what happens when one thread removes the item that another thread is busy retrieving? You might get an "Index out of range" exception. But how can one prevent this? By using locks. In VB.NET, we have SyncLock. This is mainly used to prevent two threads or instances of a class running the same piece of code at the same time. But it can also be used to lock specific objects, so that only one thread or instance changes that object at a time. Let's look at an example.

Let's declare our shared object, and a special object, used to lock the critical parts.

   1: Private Shared ItemList As New ArrayList
   2: Private Shared LockObject As New Object

Next, let's setup some methods to handle this object.

   1: Public Sub AddItem(ByVal obj As Object)
   2:     SyncLock LockObject
   3:         ItemList.Add(obj)
   4:     End SyncLock
   5: End Sub
   6:  
   7: Public Function GetItem(ByVal i As Integer) As Object
   8:     SyncLock LockObject
   9:         If (i >= 0) And (i < ItemList.Count) Then
  10:             Return ItemList(i)
  11:         End If
  12:     End SyncLock
  13: End Function

The code will look similar to remove an item from the list.

The trick is to make the locking object shared as well. This means that when a thread wants to do anything to our shared object, it has to wait until LockObject is not locked by any other thread. That should prevent any conflicts.

If you have any suggestions about improving the code, or have an interesting thought, please leave a comment below.



Dealing with file access problems in C#

clock October 16, 2008 12:06 by author devignadmin

At some point in a production environment you will come across the problem of handling a file that is locked by another process on the machine. This presents the challenge of what to do in such a case. If this does occur, .NET will throw an exception. Can we check whether a file is locked before we access it? It might be possible, but in reality it doesn't help us. Because in the time between the check and the actual file access, another process has plenty of opportunity to lock the file again, and then we are back to square one.

So, what can we do?

One way to handle this scenario is to retry our file operation until the file is not locked anymore. Of course we need to give it a maximum number of retries, otherwise we might get stuck in an endless loop (i.e. another process might have a permanent lock on the file). And if the file stays locked during our attempts, we then gracefully handle the exception. It's not the perfect solution, but it makes it more likely that our code will complete successfully.

Now, how do we accomplish this in C#? The following method could be used to copy a file with a specified number of retries.

   1: using System.IO;
   2: using System.Threading;
   3:  
   4: private bool CopyFile(string fromPath, string toPath, string newFileName, int numRetries)
   5: {
   6:     int i;
   7:     FileInfo fromFile;
   8:     DirectoryInfo destPath;
   9:     try
  10:     {
  11:         fromFile = new FileInfo(fromPath);
  12:         destPath = new DirectoryInfo(toPath);
  13:         i = 0;
  14:         while (true)
  15:         {
  16:             try
  17:             {
  18:                 i++;
  19:                 fromFile.CopyTo(Path.Combine(destPath.FullName, newFileName), true);
  20:                 return true; // Copy was successful
  21:             }
  22:             catch (IOException ioEx)
  23:             {
  24:                 if (i >= numRetries)
  25:                 {
  26:                     exit; // exit loop - maximum retries reached
  27:                 }
  28:                 else
  29:                 {
  30:                     Thread.Sleep(250); // Wait briefly before trying again
  31:                 }
  32:             }
  33:         }
  34:     }
  35:     catch (Exception ex)
  36:     {
  37:         // Handle exception
  38:         return false;
  39:     }
  40:     return false; // Copy was not completed
  41: }

 

There we go. This method is only effective with files that are locked temporarily, though. If a file is locked for longer periods, we need to handle it differently. Waiting for the file to be released is mostly not realistic, so we might want to just handle the exception and get on with things.

If you have any questions or suggestions on how to improve this code, please feel free to leave a comment below.



Controlling Windows Services in C#

clock October 7, 2008 15:12 by author devignadmin

With the .NET framework it is quite easily possible to control Windows Services programmatically. In this article I will briefly demonstrate how this can be done. To get to most methods relating to Windows Services, you need access to the System.ServiceProcess namespace. The method call to perform operations are then relatively simple.

Installing a Windows Service

First of all, let's take a look at installing a Windows Service programmatically. I use the following function to install a service, specifying the Service's .exe file as a parameter. The code look as follows:

   1: using System.ServiceProcess;
   2:  
   3: private bool InstallService(string FilePath)
   4: {
   5:     try
   6:     {
   7:         // Install Service
   8:         ManagedInstallerClass.InstallHelper(new string[] { FilePath });
   9:  
  10:         // Set Logon User
  11:         string objPath = string.Format("Win32_Service.Name='{0}'", "ServiceName");
  12:         using (ManagementObject service = new ManagementObject(new ManagementPath(objPath)))
  13:         {
  14:             object[] wmiParams = new object[11];
  15:             // User Name
  16:             wmiParams[6] = "LocalSystem";
  17:             // Password
  18:             wmiParams[7] = "";
  19:             service.InvokeMethod("Change", wmiParams);
  20:         }
  21:  
  22:         return true;
  23:     }
  24:     catch (Exception ex)
  25:     {
  26:         return false;
  27:     }
  28: }

The installation consists of only one line of code (line 8), but after that I set the logon user for the Service. In my case the service had to log on using the Local System account. If you do not need to change this, that part of the code is not necessary.

Starting and stopping Windows Service

Next, we look at starting and stopping our service. The following code performs those functions:

   1: private bool StartService(string serviceName)
   2: {
   3:     // Get list of available services
   4:     ServiceController[] services = ServiceController.GetServices();
   5:     // Loop through services
   6:     for (int i = 0; i < services.Length; i++)
   7:     {
   8:         // Check if service is the one we need
   9:         if (services[i].ServiceName == serviceName)
  10:         {
  11:             // Get a controller object for this service
  12:             ServiceController sc = new ServiceController(services[i].DisplayName, Environment.MachineName);
  13:             // If the service is not running yet, start it
  14:             if (sc.Status != ServiceControllerStatus.Running)
  15:                 sc.Start();
  16:         }
  17:     }
  18: }
  19:  
  20: private bool StopService(string serviceName)
  21: {
  22:     // Get list of available services
  23:     ServiceController[] services = ServiceController.GetServices();
  24:     // Loop through services
  25:     for (int i = 0; i < services.Length; i++)
  26:     {
  27:         // Check if service is the one we need
  28:         if (services[i].ServiceName == serviceName)
  29:         {
  30:             // Get a controller object for this service
  31:             ServiceController sc = new ServiceController(services[i].DisplayName, Environment.MachineName);
  32:             // If the service is not stopped, stop it now
  33:             if (sc.Status != ServiceControllerStatus.Stopped)
  34:                 sc.Stop();
  35:         }
  36:     }
  37: }

And those are the basics of controlling Windows Services. There are some more methods available, like pausing and resuming a service, but you can easily adapt the code above to get those functions.

If you have any problems or questions about this code, leave a comment, and I'll try to help out.



Search


Bookmark and Share

 Subscribe to this feed

Add to Technorati Favorites

Calendar

<<  March 2010  >>
SuMoTuWeThFrSa
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Archive

Tags

Categories


Blogroll

Technorati Profile

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Sign in