为什么会尝试/终于而非"使用"声明有助于避免出现竞争状况? [英] Why would try/finally rather than a "using" statement help avoid a race condition?

查看:162
本文介绍了为什么会尝试/终于而非"使用"声明有助于避免出现竞争状况?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题涉及到这里的另一个帖子评论:取消实体框架查询

This question relates to a comment in another posting here: Cancelling an Entity Framework Query

我将重现code例如,从那里净度:

I will reproduce the code example from there for clarity:

    var thread = new Thread((param) =>
    {
        var currentString = param as string;

        if (currentString == null)
        {
            // TODO OMG exception
            throw new Exception();
        }

        AdventureWorks2008R2Entities entities = null;
        try // Don't use using because it can cause race condition
        {
            entities = new AdventureWorks2008R2Entities();

            ObjectQuery<Person> query = entities.People
                .Include("Password")
                .Include("PersonPhone")
                .Include("EmailAddress")
                .Include("BusinessEntity")
                .Include("BusinessEntityContact");
            // Improves performance of readonly query where
            // objects do not have to be tracked by context
            // Edit: But it doesn't work for this query because of includes
            // query.MergeOption = MergeOption.NoTracking;

            foreach (var record in query 
                .Where(p => p.LastName.StartsWith(currentString)))
            {
                // TODO fill some buffer and invoke UI update
            }
        }
        finally
        {
            if (entities != null)
            {
                entities.Dispose();
            }
        }
    });

thread.Start("P");
// Just for test
Thread.Sleep(500);
thread.Abort();

我不能作出评论,指出

I can't make sense of the comment that says

不要使用,因为使用它会导致竞争条件

Don't use using because it can cause race condition

实体是一个局部变量,如果$ C $,C是另一个线程重新进入不会被共享,并在同一个线程中又好像完全安全(实际上等价于给定code)在其内的使用语句分配以通常的方式,而不是手动做事与尝试/最后。任何人都可以告诉我吗?

entities is a local variable and won't be shared if the code is re-entered on another thread, and within the same thread it would seem perfectly safe (and indeed equivalent to the given code) to assign it inside a "using" statement in the usual way, rather than doing things manually with the try/finally. Can anyone enlighten me?

推荐答案

是的,是有可能的竞争在使用的声明。 C#编译器转换

Yeah, there is a possible race in the using statement. The C# compiler transforms

using (var obj = new Foo()) {
    // statements
}

var obj = new Foo();
try {
   // statements
}
finally {
   if (obj != null) obj.Dispose();
}

当线程终止权的 OBJ 的赋值语句和try块之间的比赛出现。极小的可能性,但不为零。当这种情况发生的对象将不被设置。他做了改写了code。通过运动使这场比赛不能发生在try块内的分配。没有什么实际的推移,当比赛时根本错误的,处理的对象是不是必需的。

The race occurs when the thread is aborted right between the obj assignment statement and the try block. Extremely small odds but not zero. The object won't be disposed when that happens. Note how he rewrote that code by moving the assignment inside the try block so this race cannot occur. Nothing actually goes fundamentally wrong when the race occurs, disposing objects is not a requirement.

拥有了发展的线程之间进行选择中止稍微更有效,写的使用的手工报表,你首先应该选择没有得到使用Thread.Abort的习惯()。我不能推荐其实这样做,使用的语句有额外的安全措施,确保不出意外,它可以确保原始对象得到处理,即使当对象被重新分配内using语句。添加catch子句不太容易发生事故为好。在使用的声明中存在的减少的出现缺陷的可能性,一直使用它。

Having to choose between making thread aborts marginally more efficient and writing using statements by hand, you should first opt for not getting in the habit of using Thread.Abort(). I can't recommend actually doing this, the using statement has additional safety measures to ensure accidents don't happen, it makes sure that the original object gets disposed even when the object is re-assigned inside the using statement. Adding catch clauses is less prone to accidents as well. The using statement exists to reduce the likelihood of bugs, always use it.

Noodling上一些关于这个问题,答案是流行的,还有另一种常见的C#声明患有完全相同的比赛。它看起来是这样的:

Noodling on a bit about this problem, the answer is popular, there's another common C# statement that suffers from the exact same race. It looks like this:

lock (obj) {
    // statements
}

翻译为:

Monitor.Enter(obj);
// <=== Eeeek!
try {
    // statements
}
finally {
    Monitor.Exit(obj);
}

完全相同的情况下,线程可以中止后回车()调用,并在进入try块前罢工。其中prevents从正在退出()调用。这是的办法的不是一个令人讨厌的Dispose()调用不言,当然,这几乎肯定会导致死锁。问题是特定于64抖动,肮脏细节在本Joe达菲的博客文章。

Exact same scenario, the thread abort can strike after the Enter() call and before entering the try block. Which prevents the Exit() call from being made. This is way nastier than a Dispose() call that isn't made of course, this is almost certainly going to cause deadlock. The problem is specific to the x64 jitter, the sordid details are described well in this Joe Duffy blog post.

这是非常难以可靠地解决这个问题之一,移动回车()try块内调用解决不了的问题。你不能肯定的是,进入有人呼吁,所以你不能可靠地调用exit()方法,无需可能引发异常。该Monitor.ReliableEnter()方法,达菲在谈论并最终发生。在.NET版本4监视器得到了TryEnter()重载需要一个 REF布尔lockTaken 参数。现在你知道它是好的调用exit()。

It is very hard to reliably fix this one, moving the Enter() call inside the try block can't solve the problem. You cannot be sure that the Enter call was made so you cannot reliably call the Exit() method without possibly triggering an exception. The Monitor.ReliableEnter() method that Duffy was talking about did eventually happen. The .NET 4 version of Monitor got a TryEnter() overload that takes a ref bool lockTaken argument. Now you know it is okay to call Exit().

好了,可怕的东西,去BUMP在晚上,当你没看。写作code,它是安全的,断的硬盘的。你会是明智的,永远不要假设你没有写了这一切照顾的是code。这样的测试code是非常困难的,因为比赛是如此罕见。你永远无法确定。

Well, scary stuff that goes BUMP in the night when you are not looking. Writing code that's safely interruptable is hard. You'd be wise to never assume that code that you didn't write got all of this taken care of. Testing such code is extremely difficult since the race is so rare. You can never be sure.

这篇关于为什么会尝试/终于而非&QUOT;使用&QUOT;声明有助于避免出现竞争状况?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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