c# - 什么是正确的方法来防止重新进入,并确保某些操作锁定?




.net multithreading (2)

我正在设计一个基类,它在继承时将在多线程环境中针对上下文提供业务功能。 每个实例可能有长时间运行的初始化操作,所以我想使对象可重用。 为了做到这一点,我需要能够:

  1. 为这些对象中的一个分配一个上下文以允许它执行其工作
  2. 防止对象被赋予一个新的上下文,而它已经有一个
  3. 防止在对象没有上下文的情况下访问某些成员

另外,每个上下文对象可以被许多工作者对象共享。

有没有一个正确的同步原语适合我想要做的? 这是我想出的最适合我需要的模式:

private Context currentContext;

internal void BeginProcess(Context currentContext)
{
    // attempt to acquire a lock; throw if the lock is already acquired,
    // otherwise store the current context in the instance field
}

internal void EndProcess()
{
    // release the lock and set the instance field to null
}

private void ThrowIfNotProcessing()
{
    // throw if this method is called while there is no lock acquired
}

使用上述,我可以保护基类的属性和方法,不应该被访问,除非对象当前处于处理状态。

protected Context CurrentContext
{
    get
    {
        this.ThrowIfNotProcessing();
        return this.context;
    }
}

protected void SomeAction()
{
    this.ThrowIfNotProcessing();

    // do something important
}

我最初虽然是使用Monitor.Enter和相关的功能,但是这并不妨碍同线程重入(在原始线程上多次调用BeginProcess )。


在.NET中有一个同步对象不可重入,你正在寻找一个信号量。

在你做这件事情之前,先把你的鸭子放在一起,然后问自己怎么可能再次在同一个线程上调用BeginProcess()。 这是非常非常不寻常的,你的代码必须重新进入。 这通常只能在具有调度程序循环的线程上发生,GUI应用程序的UI线程就是一个常见的例子。 如果这确实是可能的,而且你实际上使用了一个信号量,那么你将会得到处理结果,你的代码将会死锁。 因为它递归到BeginProcess并停滞在信号量上。 因此永远不会完成,永远不能调用EndProcess()。 Monitor和Mutex重入的原因很充分:)


您可以使用.NET Framework 2.0附带的Semaphore类。

Semaphores的一个很好的用法是同步有限的资源。 在你的情况下,似乎你有资源喜欢Context ,你想在消费者之间分享。

您可以创建一个信号来管理资源,如:

var resourceManager = new Semaphore(0, 10);

然后使用以下方法等待BeginProcess方法中的资源可用:

resourceManager.WaitOne();

最后EndProcess方法释放EndProcess方法中的资源:

resourceManager.Release();

这里有一个关于在像你这样的情况下使用信号量的好博客

http://www.dijksterhuis.org/using-semaphores-in-c/





synchronization