Last active
March 11, 2017 08:49
-
-
Save JeffreyZhao/8630308 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
/////////////////////////////////////////////////////// | |
// Talk is cheap. Show me the code. - Linus Torvalds | |
/////////////////////////////////////////////////////// | |
public abstract class CalculatorBase : IDisposable { | |
protected void StartCore() { | |
// ... | |
} | |
protected void DisposeCore() { | |
// ... | |
} | |
public abstract void Start(); | |
public abstract void Dispose(); | |
} | |
// 需求:编写一个计算器,继承上面的CalculatorBase类,并实现Start和Dispose方法。 | |
// Start用于启动该计算器,Dispose则用于销毁,而启动和销毁的具体实现已经由基类 | |
// 的StartCore与DisposeCore提供,直接调用即可,确保成功,不会抛出一场。不过问 | |
// 题在于,Start和Dispose方法可能会被并发地执行,顺序不定,次数不定,但它们的 | |
// 实现必须满足: | |
// 1. StartCore和DisposeCore都是相对较为耗时的操作,且最多只能被调用一次。 | |
// 2. StartCore和DisposeCore一旦开始执行,则无法终止,只能执行成功。 | |
// 3. StartCore和DisposeCore必须顺序地执行,不可有任何并行。 | |
// 5. 假如调用Dispose时StartCore已经执行,则必须调用DisposeCore,否则不用。 | |
// 6. 调用Dispose意味着要销毁对象,对象销毁以后的任何访问,都不会执行任何操作。 | |
// 7. Start及Dispose方法可立即返回,不必等待StartCore或DisposeCore完成。不过, | |
// 8. 计算器本身不发起任何多线程或异步操作,一切都在Start和Dispose方法里完成。 | |
// 参考实现:一个最简单的实现方法便是用锁来保护Start和Dispose方法: | |
public class BigLockCalculator : CalculatorBase { | |
private readonly object _gate = new object(); | |
private enum Status { | |
NotStarted, | |
Started, | |
Disposed | |
} | |
private Status _status = Status.NotStarted; | |
public override void Start() { | |
lock (_gate) { | |
if (_status == Status.NotStarted) { | |
StartCore(); | |
_status = Status.Started; | |
} | |
} | |
} | |
public override void Dispose() { | |
lock (_gate) { | |
if (_status == Status.Started) { | |
DisposeCore(); | |
} | |
_status = Status.Disposed; | |
} | |
} | |
} | |
// 不过这种方法的坏处也是显而易见的,假设有许多线程同时调用Start和Dispose方法, | |
// 而某个Start线程稍早,则所有人都必须等待其调用完毕才能进行下一步判断。同理,假如 | |
// Start后进入的是个Dispose线程,则又要进行再一轮等待。 | |
// 那么,怎样可以做地更好呢? | |
/////////////////////////////////////////////////////// | |
// Talk is cheap. Show me the code. - Linus Torvalds | |
/////////////////////////////////////////////////////// | |
// 解答再此,但建议不要直接看答案,先自己想明白了再说,否则就失去意义了。 | |
// https://gist.github.com/JeffreyZhao/8644613 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
试着用队列写一个,并发性肯定没有CAS的好,但是单线程的状态机似乎好维护些