防止重新进入并确保某些操作获得锁的正确方法是什么? [英] What is the correct way to prevent reentrancy and ensure a lock is acquired for certain operations?

查看:115
本文介绍了防止重新进入并确保某些操作获得锁的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm designing a base class that, when inherited, will provide business functionality against a context in a multithreaded environment. Each instance may have long-running initialization operations, so I want to make the objects reusable. In order to do so, I need to be able to:

  1. 为这些对象之一分配上下文,以使其能够完成工作
  2. 防止对象已经拥有一个新上下文而被分配一个新上下文
  3. 在对象没有上下文的情况下防止某些成员被访问

此外,每个上下文对象可以由许多辅助对象共享.

Also, each context object can be shared by many worker objects.

是否存在符合我要执行的操作的正确同步原语?这是我提出的最适合我需要的模式:

Is there a correct synchronization primitive that fits what I'm trying to do? This is the pattern I've come up with that best fits what I need:

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
}

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

Using the above, I can protect base class properties and methods that shouldn't be accessed unless the object is currently in the processing state.

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

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

    // do something important
}

尽管我最初是使用 Monitor.Enter 和相关功能,但这不会阻止同线程重入(在原始线程上多次调用BeginProcess.)

My initial though was to use Monitor.Enter and related functions, but that doesn't prevent same-thread reentrancy (multiple calls to BeginProcess on the original thread).

推荐答案

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

There is one synchronization object in .NET that isn't re-entrant, you are looking for a Semaphore.

在执行此操作之前,请先连续执行一下操作,然后问问自己如何才能在同一线程上再次调用BeginProcess().那是非常非常不寻常的,您的代码必须重新输入才能实现.通常只能在具有调度程序循环的线程上发生这种情况,GUI应用程序的UI线程是一个常见示例.如果确实可行,并且您实际上使用了信号量,那么您也将要处理后果,您的代码将陷入僵局.由于它递归到BeginProcess并停滞在信号量上.因此永远无法完成,也永远无法调用EndProcess(). Monitor和Mutex重新进入市场是有充分理由的:)

Before you commit to this, do get your ducks in a row and ask yourself how it can be possible that BeginProcess() can be called again on the same thread. That is very, very unusual, your code has to be re-entrant for that to happen. This can normally only happen on a thread that has a dispatcher loop, the UI thread of a GUI app is a common example. If this is truly possible and you actually use a Semaphore then you'll get to deal with the consequence as well, your code will deadlock. Since it recursed into BeginProcess and stalls on the semaphore. Thus never completing and never able to call EndProcess(). There's a good reason why Monitor and Mutex are re-entrant :)

这篇关于防止重新进入并确保某些操作获得锁的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆