2016-11-20 36 views
-1

在下面的代码中,我有一个用于控制同步的类KernalRecursiveAutoResetEvent。这有一个Lock和Leave方法,它调用AutoResetEvent的WaitOne()进行锁定,Set()进行释放。我设置了一个循环,所以我可以调用一个处理共享资源的方法。在方法Increment中,我将一个int添加到共享列表中。因为离开被称为快于锁定,因此比赛分子正在缩小。有没有更好的方法来控制执行?因为检查当前线程是否等于拥有线程的条件是在通过Lock()方法设置拥有线程之前执行的,所以引发InvalidOperation异常。在递归autoresertevent上解决竞态条件

任何提示?

 class KernalRecursiveAutoResetEvent : IDisposable 
      { 
       private AutoResetEvent m_lock = new AutoResetEvent(false); 
       private int m_owningThreadId = 0; 
       private int m_recusionCount = 0; 

       public void Lock() 
       { 
        int currentThreadId = Thread.CurrentThread.ManagedThreadId; 

        if (m_owningThreadId == currentThreadId) 
        { 
         m_recusionCount++; 
         return; 
        } 

        m_lock.WaitOne(); 

        m_owningThreadId = currentThreadId; 
        m_recusionCount = 1; 
       } 

       public void Leave() 
       { 
        if (m_owningThreadId != Thread.CurrentThread.ManagedThreadId) 
         throw new InvalidOperationException(); 

        if (--m_recusionCount == 0) 
        { 
         m_owningThreadId = 0; 
         m_lock.Set(); 
        } 
       } 

       public void Dispose() 
       { 
        m_lock.Close(); 
       } 
      } 

    using (var rare = new KernalRecursiveAutoResetEvent()) 
       { 
        for (int i = 0; i < iterations; i++) 
        { 
         var t = new Thread(a => Increment(ref i, rare)); 
         t.Start(); 
         rare.Lock(); 
        } 
       } 

private static void Increment(ref int i, object _lock) 
     { 
      Increment(ref i); 

      if (_lock is KernalRecursiveAutoResetEvent) 
      { 
       var m_lock = _lock as KernalRecursiveAutoResetEvent; 
       m_lock.Leave(); 
      } 
      else if (_lock is KernalModeMutexSimpleWaitLock) 
      { 
       var m_lock = _lock as KernalModeMutexSimpleWaitLock; 
       m_lock.Leave(); 
      } 
      else if (_lock is KernalModeSemaphoreSimpleWaitLock) 
      { 
       var m_lock = _lock as KernalModeSemaphoreSimpleWaitLock; 
       m_lock.Leave(); 
      } 
      else if (_lock is KernalModeSimpleWaitLock) 
      { 
       var m_lock = _lock as KernalModeSimpleWaitLock; 
       m_lock.Leave(); 
      } 
     } 

private static void Increment(ref int i) 
     { 
      i++; 
     } 
+0

“离开被称为快于锁定” - 所以你为什么不张贴调用“离开”的代码?你可以用更传统的东西来替换你的同步原语(即'Monitor',它具有所描述的确切功能),但是如果你的代码在'Enter'之前调用'Exit',你的问题仍然会存在。 –

+0

调用离开的代码很简单,它会增加我并调用rare.Leave()(它潜在地调用AutoResetEvent.Set()。 问题不在于了解Monitor.Enter或Exit/TryExit它是了解竞争条件和控制这个.FLC静态Monitor.Enter和Leave/TryLeave等有一些基本问题,这不是理解为什么它没有锁定的问题,它不是因为控制竞态条件失败而被锁定的。如何/为什么离开之前调用锁 –

回答

1

这是不必要的复杂。您应该在将新int添加到列表的代码周围使用lock()。当然,你锁定的对象应该在所有'线程'之间通用。

例如:

var lockObj = new object(); 

for (int i = 0; i < iterations; i++) 
{ 
    // what do you mean `red i`, by the way? It's a value type. 
    var t = new Thread(a => Increment(ref i, lockObj)); 
    t.Start(); 
} 

Increment

lock (lockObj) 
{ 
    someIntList.Add(i); // or whatever. Only one thread at a time can do this! 
} 

当然,你的lockObj也可以是静态的。

另外,不要开始新的主题。改为使用Task

+0

我不想调用Monitor.Enter(锁)的原因是因为我没有理解如何锁定共享资源的问题,再加上FCL静态监视器存在一些基本问题。输入并且我想用Kernal模式同步来更好地理解。 真实我试图解决的底层问题是为什么Leave方法被称为比Enter更快?主线程到达Lock的速度比调用leave>的单独线程的执行速度要慢 –