Created
January 27, 2014 07:56
-
-
Save JeffreyZhao/8644613 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 其实这题可以写的很简单,它的关键根本不是CAS操作。 | |
// 使用一个标志(flag也好,status判断也罢)来避免Start和Dispose重入是很容易 | |
// 想到的手段,很多同学也这么做了。大部分同学遇到的问题是:假如StartCore已经 | |
// 启动,那么如何让Dispose方法等待其完成。有些同学用while (true),有些同学用 | |
// 锁,但都避免不了让Dispose线程等待Start线程。 | |
// 这里“避免等待”的关键在于要跳出思维界限:谁说DisposeCore方法一定要在Dispose | |
// 方法里执行的?我们就不能在Start里销毁对象吗? | |
public class FineLockCalculator : CalculatorBase { | |
private enum Status { | |
NotStarted, | |
Starting, | |
Started, | |
Disposed | |
} | |
private readonly object _gate = new object(); | |
private Status _status = Status.NotStarted; | |
public virtual void Start() { | |
lock (_gate) { | |
if (_status != Status.NotStarted) | |
return; | |
_status = Status.Starting; | |
} | |
StartCore(); | |
lock (_gate) { | |
if (_status == Status.Starting) { | |
_status = Status.Started; | |
return; | |
} | |
} | |
DisposeCore(); | |
} | |
public void Dispose() { | |
lock (_gate) { | |
var origStatus = _status; | |
_status = Status.Disposed; | |
if (origStatus != Status.Started) | |
return; | |
} | |
DisposeCore(); | |
} | |
} | |
// 在Dispose方法中,我们对_status进行标记,但只在确定Started的情况下才 | |
// 调用DisposeCore。同理,在Start方法中假如发现_status已经变成了Disposed, | |
// 则原地调用DisposeCore销毁对象。使用这种方法,Dispose方法完全不需要做 | |
// 任何等待,整体等待时间极短。 | |
// 清晰起见,上述代码没有使用任何CAS操作,只是对于_status读写加以简单保护。 | |
// 假如需要的话,我们也可以把三个lock轻松修改为CAS操作,但这只是起到锦上 | |
// 添花的作用。 | |
// 有些同学一上来就搞CAS,然后发现问题之后只是简单的修补,于是代码越变越 | |
// 复杂。理清思路,划分好边界,处理好边界上的竞争关系,其实逻辑说到底就是 | |
// 这么简单. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
又学了一手,太机智了。
不过仔细想想,这样对于调用者来说太trick了吧。比如我发现dispose结束了,心想太好了可以拔电源/拔网线了,但其实DisposeCore可能还没开始呢。