Home Page
  • March 28, 2024, 07:28:40 pm *
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Official site launch very soon, hurrah!


Author Topic: Thread synchronization in C#  (Read 8689 times)

Dakusan

  • Programmer Person
  • Administrator
  • Hero Member
  • *****
  • Posts: 535
    • View Profile
    • Dakusan's Domain
Thread synchronization in C#
« on: January 09, 2013, 11:18:00 pm »

Original post for Thread synchronization in C# can be found at https://www.castledragmire.com/Posts/Thread_synchronization_in_C%23.
Originally posted on: 01/09/13

I have been working heavily in C# CE (Compact Edition) v2.0 for the last 2 years for clients, and one of the very many things that I was never really happy with (in at least that version of the language, though it looks like it might plague all versions of C#) is the available thread synchronization tools. I’ve come to love the lock/wait/notify model (in Java it’s synchronized/wait/notify and in Perl it’s lock/cond_wait/cond_signal), but I have found nothing as intuitive and safe to use in C#. To alleviate this, I went ahead and wrote my own ThreadLockAndWait class that achieves this functionality.


This works the same as the POSIX lock, unlock, cond_wait, cond_signal, and cond_timedwait functions, except:
  • Lock is not required before CondSignal (it does its own inner lock and unlock)
  • If ReacquireLockAfterWait is false, in which case CondWait will not lock again after signaled and just continue immediately
  • Only 1 thread can be CondWaiting at a time (If one is CondWaiting and is signaled but not reacquired the lock, its ok for another to start CondWaiting)


public class ThreadLockAndWait
{
   private Mutex TheLock=new Mutex(), CondWaitLock=new Mutex(); //CondWaitLock makes sure 1 thread stops waiting before the next one starts waiting
   private ManualResetEvent WaitTimer=new ManualResetEvent(false);
   private string OwnersThreadName=null;
   private int OwnerLockCount=0;

   public void Lock()
   {
      TheLock.WaitOne();
      if(OwnerLockCount++==0)
         OwnersThreadName=Thread.CurrentThread.Name;
   }
   public void UnLock()
   {
      TheLock.WaitOne();
      if(OwnerLockCount==0)
      {
         TheLock.ReleaseMutex();
         throw new Exception("Cannot unlock if not locked");
      }
      TheLock.ReleaseMutex();
      if(--OwnerLockCount==0)
         OwnersThreadName=null;
      TheLock.ReleaseMutex();
   }
   public void CondWait() { RealCondWait(-1, true); }
   public void CondWait(bool ReacquireLockAfterWait) { RealCondWait(-1, ReacquireLockAfterWait); }
   public void CondTimedWait(int TimeToWait) { RealCondWait(Math.Max(0, TimeToWait), true); }
   public void CondTimedWait(int TimeToWait, bool ReacquireLockAfterWait) { RealCondWait(Math.Max(0, TimeToWait), ReacquireLockAfterWait); }
   private void RealCondWait(int TimeToWait, bool ReacquireLockAfterWait)
   {
      //Prepare to wait
      TheLock.WaitOne();
      if(OwnerLockCount==0)
      {
         TheLock.ReleaseMutex();
         throw new Exception("Cannot wait if not locked");
      }
      CondWaitLock.WaitOne(); //Release this wait before the next one starts
      WaitTimer.Reset();
      TheLock.ReleaseMutex();

      //Release all locks
      int PreviousLockCount=OwnerLockCount;
      OwnersThreadName=null;
      OwnerLockCount=0;
      if(PreviousLockCount!=1)
         System.Diagnostics.Debug.Print("Warning, mutex has multiple locks from thread!");
      for(int i=0;i<PreviousLockCount;i++)
         TheLock.ReleaseMutex();

      //Wait
      if(TimeToWait>0)
         WaitTimer.WaitOne(TimeToWait, false);
      else if(TimeToWait!=0)
         WaitTimer.WaitOne();
      CondWaitLock.ReleaseMutex();

      //Reacquire lock
      if(!ReacquireLockAfterWait)
         return;
      for(int i=0;i<PreviousLockCount;i++)
         TheLock.WaitOne();
      OwnerLockCount=PreviousLockCount;
      OwnersThreadName=Thread.CurrentThread.Name;
   }

   public void CondSignal()
   {
      TheLock.WaitOne();
      WaitTimer.Set();
      TheLock.ReleaseMutex();
   }
}
Logged