If you require more control over locking and unlocking of critical sections, you might want to try using the overloaded static Monitor.TryEnter methods. These methods allow more flexibility by introducing a timeout value. The lock keyword will attempt to acquire a lock on a critical section indefinitely. However, with the TryEnter method, you can enter a timeout value in milliseconds (as an integer) or as a TimeSpan structure. The TryEnter methods return true if a lock was acquired and false if it was not. Note that the overload of the TryEnter method that accepts only a single parameter does not block for any amount of time. This method returns immediately, regardless of whether the lock was acquired.

The updated class using the Monitor methods is shown here:

using System;
using System.Threading;

public sealed class MonitorMethodAccess
{
    private MonitorMethodAccess ( ) {}

    private static int numericField = 1;
    private static object syncObj = new object();

    public static void IncrementNumericField()
    {
        if (Monitor.TryEnter(syncObj, 250))
        {
            try
            {
                ++numericField;
            }
            finally
            {
                Monitor.Exit(syncObj);
            }
        }
    }

    public static void ModifyNumericField(int newValue)
    {
        if (Monitor.TryEnter(syncObj, 250))
        {
            try
            {
                numericField = newValue;
            }
            finally
            {
                Monitor.Exit(syncObj);
            }
        }
    }

    public static int ReadNumericField()
    {
        if (Monitor.TryEnter(syncObj, 250))
        {
            int readValue = 0;

            tryfinally
            {
                Monitor.Exit(syncObj);
            }

            return (readValue);
        }

        return (-1);
    }

}

Note that with the TryEnter methods, you should always check to see whether the lock was in fact acquired. If it is not, your code should wait and try again, or return to the caller.

You might think at this point that all of the methods are thread-safe. Individually, they are, but what if you are trying to call them and you expect synchronized access between two of the methods? If ModifyNumericField and ReadNumericField are used one after the other by Class 1 on Thread 1 at the same time Class 2 is using these methods on Thread 2, locking or Monitor calls will not prevent Class 2 from modifying the value before Thread 1 reads it. Here is a series of actions that demonstrates this:

Class 1 Thread 1
Calls ModifyNumericField with 10.

Class 2 Thread 2
Calls ModifyNumericField with 15.

Class 1 Thread 1
Calls ReadNumericField and gets 15, not 10.

Class 2 Thread 2
Calls ReadNumericField and gets 15, which it expected.

In order to solve this problem of synchronizing reads and writes, the calling class needs to manage the interaction. The external class could accomplish this by using the Monitor class to establish a lock on the type object, as shown here:

int num = 0;
if (Monitor.TryEnter(typeof(MonitorMethodAccess),250))
{
    MonitorMethodAccess.ModifyNumericField(10);
    num = MonitorMethodAccess.ReadNumericField();
    Monitor.Exit(typeof(MonitorMethodAccess));
}
Console.WriteLine(num);

Popularity: 8% [?]