1

我试图找到一种方法来提供对资源的独占访问,同时提供有关锁状态 (_isWorking) 的信息以供其他类读取。

到目前为止,这是我想出的:

    private int _isWorking = 0;

    public bool IsWorking
    {
        get { return Interlocked.CompareExchange(ref _isWorking, 0, 0) == 1; }
    }

    public void LaunchProcess()
    {
        if (Interlocked.CompareExchange(ref _isWorking, 1, 0) == 0)
        {
            try
            {
                DoExpansiveProcess();
            }
            finally
            {
                Interlocked.Exchange(ref _isWorking, 0);
            }
        }
    }

    public void DoExpansiveProcess()
    {
        Thread.Sleep(30000);
    }

它不能完全像锁一样工作,因为第二个线程在看到一个线程已经在运行该进程时,只会离开该方法并且什么都不做。

这是执行此操作的正确方法,还是有更适合此目的的 C# 3.5 结构?

以及如何实现“真正的”锁定场景,第二个线程在第一个线程完成后仍会执行该方法,同时提供有关状态的信息?

4

3 回答 3

1

假设我正确理解了您的问题,那么我认为您所追求的是Monitor.TryEnter超时值为 0 的方法。它会尝试获取锁,但超时为 0 时,它总是会立即返回指示锁是否为实际获得。这里的含义是,如果没有获得锁,则假定它已经被其他人获得。问题是,如果返回,true那么您必须立即通过调用Monitor.Exit.

也许这将是一个更好的解决方案:

public class Worker
{
  private Object m_LockObject = new Object();
  private volatile bool m_IsWorking = false;

  public bool IsWorking
  {
    get { return m_IsWorking; }
  }

  public void LaunchProcess()
  {
    lock (m_LockObject)
    {
      m_IsWorking = true;
      DoExpansiveProcess();
      m_IsWorking = false;
    }
  }
}
于 2010-06-24T13:02:57.917 回答
0

System.Threading.ManualResetEvent也许可以在这里提供帮助。只需对它执行 WaitOne() 即可。如果它正在被使用,那么它将返回为假。如果它不使用,它是可用的。

WaitOne() 重载之一需要以毫秒为单位的等待时间。如果您使用 WaitOne(0) 则等待将以非阻塞方式立即返回。

您应该对 .Net 提供的同步原语进行一些研究:

System.Threading.Monitor lock() { }
System.Threading.ManualResetEvent
System.Threading.AutoResetEvent
System.Threading.Semaphore
System.Threading.Mutex
于 2010-06-24T09:56:53.110 回答
0

我认为您的方法通常应该是正确的,并且肯定会比使用 ManualResetEvent (如果它完全相关)快得多 - 因为 ManualResetEvent 包装了底层的非托管原语。

然而,为了使这种方法安全,_isWorking 必须是私有的。

于 2010-06-24T10:13:54.963 回答