views:

653

answers:

5

What is it and how to use?

I need that as I have a timer that inserts into DB every second, and I have a shared resource between timer handler and the main thread. I want to gurantee that if the timer handler takes more than one second in the insertion the waited threads should be executed in order. This is a sample code for my timer handler

private void InsertBasicVaraibles(object param)
{
            try
            {
                DataTablesMutex.WaitOne();//mutex for my shared resources
                //insert into DB
            }
            catch (Exception ex)
            {
                //Handle
            }
            finally
            {
                DataTablesMutex.ReleaseMutex();
            }
}

But currently the mutex does not guarantee any order. There is not answer after I put the detailed question!!!

A: 

There is no guaranteed order on any built-in synchronisation objects: http://msdn.microsoft.com/en-us/library/ms684266(VS.85).aspx

If you want a guaranteed order you'll have to try and build something yourself, note though that it's not as easy as it might sound, especially when multiple threads reach the synchronisation point at (close to) the same time. To some extent the order they will be released will always be 'random' since you cannot predict in which order the point is reached, so does it really matter?

jerryjvl
The link is of course about the OS primitives... at some point the .NET ones will be built on top of these, so I guess that implies FIFO cannot be guaranteed... see also Jon's answer.
jerryjvl
+8  A: 

Just reading Joe Duffy's "Concurrent Programming on Windows" it sounds like you'll usually get FIFO behaviour from .NET monitors, but there are some situations where that won't occur.

Page 273 of the book says: "Because monitors use kernel objects internally, they exhibit the same roughly-FIFO behavior that the OS synchronization mechanisms also exhibit (described in the previous chapter). Monitors are unfair, so if another thread sneaks in and acquires the lock before an awakened waiting thread tries to acquire the lock, the sneaky thread is permitted to acquire the lock."

I can't immediately find the section referenced "in the previous chapter" but it does note that locks have been made deliberately unfair in recent editions of Windows to improve scalability and reduce lock convoys.

Do you definitely need your lock to be FIFO? Maybe there's a different way to approach the problem. I don't know of any locks in .NET which are guaranteed to be FIFO.

Jon Skeet
Jon Skeet is as usual, correct - Win2k3 SP2(ish?) and up do not have 100% fair locking, and this is intentional.
Paul Betts
+5  A: 

You'll need to write your own class to do this, I found this example (pasted because it looks as though the site's domain has lapsed):

using System.Threading;

public sealed class QueuedLock
{
    private object innerLock;
    private volatile int ticketsCount = 0;
    private volatile int ticketToRide = 1;

    public QueuedLock()
    {
        innerLock = new Object();
    }

    public void Enter()
    {
        int myTicket = Interlocked.Increment(ref ticketsCount);
        Monitor.Enter(innerLock);
        while (true)
        {

            if (myTicket == ticketToRide)
            {
                return;
            }
            else
            {
                Monitor.Wait(innerLock);
            }
        }
    }

    public void Exit()
    {
        Interlocked.Increment(ref ticketToRide);
        Monitor.PulseAll(innerLock);
        Monitor.Exit(innerLock);
    }
}

Example of usage:

QueuedLock queuedLock = new QueuedLock();

try
{
   queuedLock.Enter();
   // here code which needs to be synchronized
   // in correct order
}
finally
{
 queuedLock.Exit();
}

Source via Google cache

Matthew Brindley
This would be prettier if QueuedLock was IDisposable
Sam Saffron
+5  A: 

You should re-design your system to not rely on the execution order of the threads. For example, rather than have your threads make a DB call that might take more than one second, have your threads place the command they would execute into a data structure like a queue (or a heap if there is something that says "this one should be before another one"). Then, in spare time, drain the queue and do your db inserts one at a time in the proper order.

JP Alioto
A: 

Actually the answers are good, but I solved the problem by removing the timer and run the method (timer-handler previously) into background thread as follows

    private void InsertBasicVaraibles()
    {
         int functionStopwatch = 0;
         while(true)
         {

           try
           {
             functionStopwatch = Environment.TickCount;
             DataTablesMutex.WaitOne();//mutex for my shared resources
             //insert into DB 
           }
           catch (Exception ex)
           {
             //Handle            
           }
           finally            
           {                
              DataTablesMutex.ReleaseMutex();
           }

           //simulate the timer tick value
           functionStopwatch = Environment.TickCount - functionStopwatch;
           int diff = INSERTION_PERIOD - functionStopwatch;
           int sleep = diff >= 0 ?  diff:0;
           Thread.Sleep(sleep);
        }
    }
Ahmed Said