提供有关 .NET 3.5 中状态信息的锁定机制

发布于 2024-09-07 08:36:26 字数 820 浏览 3 评论 0原文

我试图找到一种方法来提供对资源的独占访问,同时提供有关锁状态(_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 结构?

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

I'm trying to find a way to provide exclusive access to a resource, while at the same time providing information about the state of the lock (_isWorking) for other classes to read.

Here's what I have come up with so far :

    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);
    }

It does not work exactly as a lock since the second thread, upon seeing that a thread is already running the process, will just leave the method and do nothing.

Is it the correct way to do this or are there any C# 3.5 structure more adapted for the purpose?

And how to implement a 'real' lock scenario, where the second thread would still execute the method after the first one finishes, while providing information about the state?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花之痕靓丽 2024-09-14 08:36:26

假设我正确理解你的问题,那么我认为你所追求的是超时值为 0 的 Monitor.TryEnter 方法。它将尝试获取锁,但超时值为 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;
    }
  }
}

Assuming that I understand your question correctly then I think what you are after is the Monitor.TryEnter method with a timeout value of 0. It will attempt to acquire the lock, but with a timeout of 0 it will always return immediately with value indicating whether the lock was actually acquired. The implication here is that if the lock was not acquired then it is assumed that it is already acquired by someone else. The problem is that if returns true then you would have to immediately release it with a call to Monitor.Exit.

Perhaps this would be a better solution:

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;
    }
  }
}
娇柔作态 2024-09-14 08:36:26

System.Threading.ManualResetEvent 可能可以在这里提供帮助。只需对其执行 WaitOne() 即可。如果它被使用,那么它将返回错误。如果未使用,则可以使用。

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

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

System.Threading.Monitor lock() { }
System.Threading.ManualResetEvent
System.Threading.AutoResetEvent
System.Threading.Semaphore
System.Threading.Mutex

System.Threading.ManualResetEvent might be able to help here. Just do a WaitOne() against it. If it's being used then it will come back as false. If it isn't in use it is available.

One of the WaitOne() overloads takes a time in milliseconds to wait. If you use WaitOne(0) then the wait will return immediately in a non blocking way.

You should do some research into the synchronisation primitives that .Net offers:

System.Threading.Monitor lock() { }
System.Threading.ManualResetEvent
System.Threading.AutoResetEvent
System.Threading.Semaphore
System.Threading.Mutex
思念满溢 2024-09-14 08:36:26

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

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

I think your approach should in general be correct and will definitely be much faster than using a ManualResetEvent (if its at all relevant) - because ManualResetEvent wraps underlying unmanaged primitive.

To make this approach safe however, _isWorking has to be private.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文