ืคื™ืœื•ืกื•ืคื™ื ืžืื›ื™ืœื™ื ื”ื™ื˜ื‘ ืื• ืชื›ื ื•ืช NET ืชื—ืจื•ืชื™

ืคื™ืœื•ืกื•ืคื™ื ืžืื›ื™ืœื™ื ื”ื™ื˜ื‘ ืื• ืชื›ื ื•ืช NET ืชื—ืจื•ืชื™

ื‘ื•ืื• ื ืจืื” ืื™ืš ืชื›ื ื•ืช ืžืงื‘ื™ืœ ื•ืžืงื‘ื™ืœ ืขื•ื‘ื“ ื‘-.Net, ืชื•ืš ืฉื™ืžื•ืฉ ื‘ื‘ืขื™ื™ืช ื”ืื•ื›ืœ ืฉืœ ืคื™ืœื•ืกื•ืคื™ื ื›ื“ื•ื’ืžื”. ื”ืชื•ื›ื ื™ืช ื”ื™ื ื›ื–ื•, ื”ื—ืœ ืžืกื ื›ืจื•ืŸ ื—ื•ื˜ื™ื/ืชื”ืœื™ื›ื™ื, ื•ืขื“ ืœืžื•ื“ืœ ื”ืฉื—ืงืŸ (ื‘ื—ืœืงื™ื ื”ื‘ืื™ื). ื”ืžืืžืจ ืขืฉื•ื™ ืœื”ื™ื•ืช ืฉื™ืžื•ืฉื™ ืขื‘ื•ืจ ื”ื”ื™ื›ืจื•ืช ื”ืจืืฉื•ื ื” ืื• ืขืœ ืžื ืช ืœืจืขื ืŸ ืืช ื”ื™ื“ืข ืฉืœืš.

ืœืžื” ืœืขืฉื•ืช ืืช ื–ื” ื‘ื›ืœืœ? ื˜ืจื ื–ื™ืกื˜ื•ืจื™ื ืžื’ื™ืขื™ื ืœื’ื•ื“ืœื ื”ืžื™ื ื™ืžืœื™, ื—ื•ืง ืžื•ืจ ื ืฉืขืŸ ืขืœ ื”ื’ื‘ืœืช ืžื”ื™ืจื•ืช ื”ืื•ืจ ื•ืœื›ืŸ ื ืฆืคื™ืช ืขืœื™ื™ื” ื‘ืžืกืคืจ, ื ื™ืชืŸ ืœื™ื™ืฆืจ ื™ื•ืชืจ ื˜ืจื ื–ื™ืกื˜ื•ืจื™ื. ื‘ืžืงื‘ื™ืœ, ื›ืžื•ืช ื”ื ืชื•ื ื™ื ื’ื“ืœื” ื•ื”ืžืฉืชืžืฉื™ื ืžืฆืคื™ื ืœืชื’ื•ื‘ื” ืžื™ื™ื“ื™ืช ืžื”ืžืขืจื›ื•ืช. ื‘ืžืฆื‘ ื›ื–ื”, ืชื›ื ื•ืช "ืจื’ื™ืœ", ื›ืฉื™ืฉ ืœื ื• ืฉืจืฉื•ืจ ื‘ื™ืฆื•ืข ืื—ื“, ื›ื‘ืจ ืœื ื™ืขื™ืœ. ืืชื” ืฆืจื™ืš ืื™ื›ืฉื”ื• ืœืคืชื•ืจ ืืช ื”ื‘ืขื™ื” ืฉืœ ื‘ื™ืฆื•ืข ื‘ื• ื–ืžื ื™ืช ืื• ื‘ืžืงื‘ื™ืœ. ื™ืชืจื” ืžื›ืš, ื‘ืขื™ื” ื–ื• ืงื™ื™ืžืช ื‘ืจืžื•ืช ืฉื•ื ื•ืช: ื‘ืจืžืช ื”ืฉืจืฉื•ืจื™ื, ื‘ืจืžืช ื”ืชื”ืœื™ื›ื™ื, ื‘ืจืžืช ื”ืžื›ื•ื ื•ืช ื‘ืจืฉืช (ืžืขืจื›ื•ืช ืžื‘ื•ื–ืจื•ืช). ืœ-.NET ื™ืฉ ื˜ื›ื ื•ืœื•ื’ื™ื•ืช ืื™ื›ื•ืชื™ื•ืช ืฉื ื‘ื“ืงื• ื‘ื–ืžืŸ ืœืคืชืจื•ืŸ ืžื”ื™ืจ ื•ื™ืขื™ืœ ืฉืœ ื‘ืขื™ื•ืช ื›ืืœื”.

ืžืฉื™ืžื”

Edsger Dijkstra ื”ืฆื™ื’ ื‘ืขื™ื” ื–ื• ืœืชืœืžื™ื“ื™ื• ื›ื‘ืจ ื‘ืฉื ืช 1965. ื”ื ื™ืกื•ื— ืฉื ืงื‘ืข ื”ื•ื ื›ื“ืœืงืžืŸ. ื™ืฉ ืžืกืคืจ ืžืกื•ื™ื (ื‘ื“ืจืš ื›ืœืœ ื—ืžื™ืฉื”) ืฉืœ ืคื™ืœื•ืกื•ืคื™ื ื•ืžืกืคืจ ื–ื”ื” ืฉืœ ืžื–ืœื’ื•ืช. ื”ื ื™ื•ืฉื‘ื™ื ืœื™ื“ ืฉื•ืœื—ืŸ ืขื’ื•ืœ, ืžืชืคืฆืœื™ื ื‘ื™ื ื™ื”ื. ืคื™ืœื•ืกื•ืคื™ื ื™ื›ื•ืœื™ื ืœืื›ื•ืœ ืžื”ืฆืœื—ื•ืช ืฉืœื”ื ืฉืœ ืื•ื›ืœ ืื™ื ืกื•ืคื™, ืœื—ืฉื•ื‘ ืื• ืœื—ื›ื•ืช. ื›ื“ื™ ืœืื›ื•ืœ ืคื™ืœื•ืกื•ืฃ, ืืชื” ืฆืจื™ืš ืœืงื—ืช ืฉื ื™ ืžื–ืœื’ื•ืช (ื”ืื—ืจื•ืŸ ื—ื•ืœืง ืืช ื”ืžื–ืœื’ ืขื ื”ืจืืฉื•ืŸ). ื”ืจืžื” ื•ื”ื ื—ืช ืžื–ืœื’ ื”ืŸ ืฉืชื™ ืคืขื•ืœื•ืช ื ืคืจื“ื•ืช. ื›ืœ ื”ืคื™ืœื•ืกื•ืคื™ื ืฉื•ืชืงื™ื. ื”ืžืฉื™ืžื” ื”ื™ื ืœืžืฆื•ื ืืœื’ื•ืจื™ืชื ื›ื–ื” ืฉื›ื•ืœื ื™ื—ืฉื‘ื• ื•ื™ื”ื™ื• ืžืœืื™ื ื’ื ืื—ืจื™ 54 ืฉื ื™ื.

ืจืืฉื™ืช, ื‘ื•ืื• ื ื ืกื” ืœืคืชื•ืจ ื‘ืขื™ื” ื–ื• ื‘ืืžืฆืขื•ืช ืฉื™ืžื•ืฉ ื‘ืžืจื—ื‘ ืžืฉื•ืชืฃ. ื”ืžื–ืœื’ื•ืช ืžื•ื ื—ื™ื ืขืœ ื”ืฉื•ืœื—ืŸ ื”ืžืฉื•ืชืฃ ื•ื”ืคื™ืœื•ืกื•ืคื™ื ืคืฉื•ื˜ ืœื•ืงื—ื™ื ืื•ืชื ื›ืฉื”ื ื•ืžื—ื–ื™ืจื™ื ืื•ืชื. ื›ืืŸ ื™ืฉ ื‘ืขื™ื•ืช ื‘ืกื ื›ืจื•ืŸ, ืžืชื™ ื‘ื“ื™ื•ืง ืœืงื—ืช ื”ื™ืžื•ืจื™ื ื‘ื˜ื•ื—ื™ื? ืžื” ืื ืื™ืŸ ืžื–ืœื’? ื•ื›ื•' ืื‘ืœ ืงื•ื“ื ื ืชื—ื™ืœ ืืช ื”ืคื™ืœื•ืกื•ืคื™ื.

ื›ื“ื™ ืœื”ืชื—ื™ืœ ืฉืจืฉื•ืจื™ื, ืื ื• ืžืฉืชืžืฉื™ื ื‘ืžืื’ืจ ื—ื•ื˜ื™ื ื“ืจืš Task.Run ืฉื™ื˜ื”:

var cancelTokenSource = new CancellationTokenSource();
Action<int> create = (i) => RunPhilosopher(i, cancelTokenSource.Token);
for (int i = 0; i < philosophersAmount; i++) 
{
    int icopy = i;
    // ะŸะพะผะตัั‚ะธั‚ัŒ ะทะฐะดะฐั‡ัƒ ะฒ ะพั‡ะตั€ะตะดัŒ ะฟัƒะปะฐ ะฟะพั‚ะพะบะพะฒ. ะœะตั‚ะพะด RunDeadlock ะฝะต ะทะฐะฟัƒัะบะฐะตั‚ัŒัั 
    // ัั€ะฐะทัƒ, ะฐ ะถะดะตั‚ ัะฒะพะตะณะพ ะฟะพั‚ะพะบะฐ. ะัะธะฝั…ั€ะพะฝะฝั‹ะน ะทะฐะฟัƒัะบ.
    philosophers[i] = Task.Run(() => create(icopy), cancelTokenSource.Token);
}

ืžืื’ืจ ื”ืฉืจืฉื•ืจื™ื ื ื•ืขื“ ืœื™ื™ืขืœ ืืช ื”ื™ืฆื™ืจื” ื•ื”ืžื—ื™ืงื” ืฉืœ ืฉืจืฉื•ืจื™ื. ืœืžืื’ืจ ื”ื–ื” ื™ืฉ ืชื•ืจ ืขื ืžืฉื™ืžื•ืช ื•ื”-CLR ื™ื•ืฆืจ ืื• ืžืกื™ืจ ืฉืจืฉื•ืจื™ื ื‘ื”ืชืื ืœืžืกืคืจ ื”ืžืฉื™ืžื•ืช ื”ืœืœื•. ืžืื’ืจ ืื—ื“ ืœื›ืœ AppDomains. ื™ืฉ ืœื”ืฉืชืžืฉ ื‘ื‘ืจื™ื›ื” ื–ื• ื›ืžืขื˜ ืชืžื™ื“, ื›ื™. ืื™ืŸ ืฆื•ืจืš ืœื”ืชืขืกืง ื‘ื™ืฆื™ืจื”, ืžื—ื™ืงืช ืฉืจืฉื•ืจื™ื, ื”ืชื•ืจื™ื ืฉืœื”ื ื•ื›ื•'. ืืคืฉืจ ื‘ืœื™ ืžืื’ืจ, ืื‘ืœ ืื– ืฆืจื™ืš ืœื”ืฉืชืžืฉ ื‘ื• ื™ืฉื™ืจื•ืช Thread, ื–ื” ืฉื™ืžื•ืฉื™ ืœืžืงืจื™ื ืฉื‘ื”ื ืืชื” ืฆืจื™ืš ืœืฉื ื•ืช ืืช ื”ืขื“ื™ืคื•ืช ืฉืœ ืฉืจืฉื•ืจ, ื›ืืฉืจ ื™ืฉ ืœื ื• ืคืขื•ืœื” ืืจื•ื›ื”, ืขื‘ื•ืจ ืฉืจืฉื•ืจ ืงื“ืžื™ ื•ื›ื•'.

ื‘ืžื™ืœื™ื ืื—ืจื•ืช, System.Threading.Tasks.Task ื”ื›ื™ืชื” ื–ื”ื” Thread, ืื‘ืœ ืขื ื›ืœ ืžื™ื ื™ ื ื•ื—ื•ืช: ื”ื™ื›ื•ืœืช ืœื”ืคืขื™ืœ ืžืฉื™ืžื” ืื—ืจื™ ื‘ืœื•ืง ืฉืœ ืžืฉื™ืžื•ืช ืื—ืจื•ืช, ืœื”ื—ื–ื™ืจ ืื•ืชืŸ ืžืคื•ื ืงืฆื™ื•ืช, ืœื”ืคืจื™ืข ืœื”ืŸ ื‘ืฆื•ืจื” ื ื•ื—ื” ื•ืขื•ื“. ื•ื›ื•' ื”ื ื ื—ื•ืฆื™ื ื›ื“ื™ ืœืชืžื•ืš ื‘ื‘ื ื™ื™ื” ืืกื™ื ื›ืจื•ื ื™ืช / ืžืžืชื™ื ื” (ื“ืคื•ืก ืืกื™ื ื›ืจื•ื ื™ ืžื‘ื•ืกืก ืžืฉื™ืžื•ืช, ืกื•ื›ืจ ืชื—ื‘ื™ืจื™ ืœื”ืžืชื ื” ืœืคืขื•ืœื•ืช IO). ื ื“ื‘ืจ ืขืœ ื–ื” ืžืื•ื—ืจ ื™ื•ืชืจ.

CancelationTokenSource ื›ืืŸ ื–ื” ื ื—ื•ืฅ ื›ื“ื™ ืฉื”ืคืชื™ืœ ื™ื•ื›ืœ ืœื”ืคืกื™ืง ืืช ืขืฆืžื• ืขื ื”ืื•ืช ืฉืœ ื”ื—ื•ื˜ ื”ืงื•ืจื.

ื‘ืขื™ื•ืช ืกื ื›ืจื•ืŸ

ืคื™ืœื•ืกื•ืคื™ื ื—ืกื•ืžื™ื

ืื•ืงื™ื™, ืื ื—ื ื• ื™ื•ื“ืขื™ื ืื™ืš ืœื™ืฆื•ืจ ืฉืจืฉื•ืจื™ื, ื‘ื•ืื• ื ื ืกื” ืœืื›ื•ืœ ืืจื•ื—ืช ืฆื”ืจื™ื™ื:

// ะšั‚ะพ ะบะฐะบะธะต ะฒะธะปะบะธ ะฒะทัะป. ะš ะฟั€ะธะผะตั€ัƒ: 1 1 3 3 - 1ะน ะธ 3ะน ะฒะทัะปะธ ะฟะตั€ะฒั‹ะต ะดะฒะต ะฟะฐั€ั‹.
private int[] forks = Enumerable.Repeat(0, philosophersAmount).ToArray();

// ะขะพ ะถะต, ั‡ั‚ะพ RunPhilosopher()
private void RunDeadlock(int i, CancellationToken token) 
{
    // ะ–ะดะฐั‚ัŒ ะฒะธะปะบัƒ, ะฒะทัั‚ัŒ ะตั‘. ะญะบะฒะธะฒะฐะปะตะฝั‚ะฝะพ: 
    // while(true) 
    //     if forks[fork] == 0 
    //          forks[fork] = i+1
    //          break
    //     Thread.Sleep() ะธะปะธ Yield() ะธะปะธ SpinWait()
    void TakeFork(int fork) =>
        SpinWait.SpinUntil(() => 
            Interlocked.CompareExchange(ref forks[fork], i+1, 0) == 0);

    // ะ”ะปั ะฟั€ะพัั‚ะพั‚ั‹, ะฝะพ ะผะพะถะฝะพ ั Interlocked.Exchange:
    void PutFork(int fork) => forks[fork] = 0;

    while (true)
    {
        TakeFork(Left(i));
        TakeFork(Right(i));
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        PutFork(Left(i));
        PutFork(Right(i));
        Think(i);

        // ะ—ะฐะฒะตั€ัˆะธั‚ัŒ ั€ะฐะฑะพั‚ัƒ ะฟะพ-ั…ะพั€ะพัˆะตะผัƒ.
        token.ThrowIfCancellationRequested();
    }
}

ื›ืืŸ ืื ื—ื ื• ืžื ืกื™ื ืงื•ื“ื ื›ืœ ืœืงื—ืช ืืช ื”ืžื–ืœื’ ื”ืฉืžืืœื™, ื•ืื—ืจ ื›ืš ืืช ื”ืžื–ืœื’ ื”ื™ืžื ื™, ื•ืื ื–ื” ืžืกืชื“ืจ, ืื– ืื ื—ื ื• ืื•ื›ืœื™ื ื•ืžื—ื–ื™ืจื™ื ืื•ืชื. ืœืงื™ื—ืช ืžื–ืœื’ ืื—ื“ ื–ื” ืื˜ื•ืžื™, ื›ืœื•ืžืจ. ืฉื ื™ ื—ื•ื˜ื™ื ืœื ื™ื›ื•ืœื™ื ืœืงื—ืช ืื—ื“ ื‘ื• ื–ืžื ื™ืช (ืœื ื ื›ื•ืŸ: ื”ืจืืฉื•ืŸ ืงื•ืจื ืฉื”ืžื–ืœื’ ืคื ื•ื™, ื”ืฉื ื™ - ื’ื ื”ืจืืฉื•ืŸ ืœื•ืงื—, ื”ืฉื ื™ ืœื•ืงื—). ืœื–ื” Interlocked.CompareExchange, ืืฉืจ ื—ื™ื™ื‘ ืœื”ื™ื•ืช ืžื™ื•ืฉื ืขื ื”ื•ืจืืช ืžืขื‘ื“ (TSL, XCHG), ื”ื ื•ืขืœ ืคื™ืกืช ื–ื™ื›ืจื•ืŸ ืœืงืจื™ืื” ื•ื›ืชื™ื‘ื” ื‘ืจืฆืฃ ืื˜ื•ืžื™. ื•- SpinWait ืฉื•ื•ื” ืขืจืš ืœืžื‘ื ื” while(true) ืจืง ืขื ืงืฆืช "ืงืกื" - ื”ื—ื•ื˜ ืœื•ืงื— ืืช ื”ืžืขื‘ื“ (Thread.SpinWait), ืื‘ืœ ืœืคืขืžื™ื ืžืขื‘ื™ืจ ืืช ื”ืฉืœื™ื˜ื” ืœืฉืจืฉื•ืจ ืื—ืจ (Thread.Yeild) ืื• ื ืจื“ื (Thread.Sleep).

ืื‘ืœ ื”ืคืชืจื•ืŸ ื”ื–ื” ืœื ืขื•ื‘ื“, ื›ื™ ื”ื–ืจื™ืžื•ืช ื‘ืงืจื•ื‘ (ืขื‘ื•ืจื™ ืชื•ืš ืฉื ื™ื™ื”) ื ื—ืกืžื•ืช: ื›ืœ ื”ืคื™ืœื•ืกื•ืคื™ื ืœื•ืงื—ื™ื ืืช ื”ืžื–ืœื’ ื”ืฉืžืืœื™ ืฉืœื”ื, ืื‘ืœ ืœื ืืช ื”ืžื–ืœื’ ื”ื™ืžื ื™. ืœืžืขืจืš ื”ืžื–ืœื’ื•ืช ื™ืฉ ืื– ืืช ื”ืขืจื›ื™ื: 1 2 3 4 5.

ืคื™ืœื•ืกื•ืคื™ื ืžืื›ื™ืœื™ื ื”ื™ื˜ื‘ ืื• ืชื›ื ื•ืช NET ืชื—ืจื•ืชื™

ื‘ืื™ื•ืจ, ื—ื•ื˜ื™ื ื—ื•ืกืžื™ื (ืžื‘ื•ื™ ืกืชื•ื). ื™ืจื•ืง - ื‘ื™ืฆื•ืข, ืื“ื•ื - ืกื ื›ืจื•ืŸ, ืืคื•ืจ - ื”ื—ื•ื˜ ื™ืฉืŸ. ื”ืžืขื•ื™ื ื™ื ืžืฆื™ื™ื ื™ื ืืช ืฉืขืช ื”ื”ืชื—ืœื” ืฉืœ ืžืฉื™ืžื•ืช.

ื”ืจืขื‘ ืฉืœ ื”ืคื™ืœื•ืกื•ืคื™ื

ืืžื ื ืื™ืŸ ืฆื•ืจืš ืœื—ืฉื•ื‘ ื‘ืžื™ื•ื—ื“ ืขืœ ืื•ื›ืœ, ืื‘ืœ ื”ืจืขื‘ ื’ื•ืจื ืœื›ืœ ืื—ื“ ืœื•ื•ืชืจ ืขืœ ื”ืคื™ืœื•ืกื•ืคื™ื”. ื‘ื•ืื• ื ื ืกื” ืœื“ืžื•ืช ืืช ื”ืžืฆื‘ ืฉืœ ื”ืจืขื‘ื” ืฉืœ ื—ื•ื˜ื™ื ื‘ื‘ืขื™ื” ืฉืœื ื•. ื”ืจืขื‘ื” ื”ื™ื ื›ืฉื—ื•ื˜ ืคื•ืขืœ, ืื‘ืœ ื‘ืœื™ ืขื‘ื•ื“ื” ืžืฉืžืขื•ืชื™ืช, ื‘ืžื™ืœื™ื ืื—ืจื•ืช, ื–ื” ืื•ืชื• ืžื‘ื•ื™ ืกืชื•ื, ืจืง ืขื›ืฉื™ื• ื”ื—ื•ื˜ ืœื ื™ืฉืŸ, ืืœื ืžื—ืคืฉ ื‘ืื•ืคืŸ ืืงื˜ื™ื‘ื™ ืžื” ืœืื›ื•ืœ, ืื‘ืœ ืื™ืŸ ืื•ื›ืœ. ืขืœ ืžื ืช ืœื”ื™ืžื ืข ืžื—ืกื™ืžื” ืชื›ื•ืคื”, ื ื—ื–ื™ืจ ืืช ื”ืžื–ืœื’ ื‘ื—ื–ืจื” ืื ืœื ื™ื›ื•ืœื ื• ืœืงื—ืช ืขื•ื“ ืื—ื“.

// ะขะพ ะถะต ั‡ั‚ะพ ะธ ะฒ RunDeadlock, ะฝะพ ั‚ะตะฟะตั€ัŒ ะบะปะฐะดะตะผ ะฒะธะปะบัƒ ะฝะฐะทะฐะด ะธ ะดะพะฑะฐะฒะปัะตะผ ะฟะปะพั…ะธั… ั„ะธะปะพัะพั„ะพะฒ.
private void RunStarvation(int i, CancellationToken token)
{
    while (true)
    {
        bool hasTwoForks = false;
        var waitTime = TimeSpan.FromMilliseconds(50);
        // ะŸะปะพั…ะพะน ั„ะธะปะพัะพั„ะพะฒ ะผะพะถะตั‚ ัƒะถะต ะธะผะตั‚ัŒ ะฒะธะปะบัƒ:
        bool hasLeft = forks[Left(i)] == i + 1;
        if (hasLeft || TakeFork(Left(i), i + 1, waitTime))
        {
            if (TakeFork(Right(i), i + 1, TimeSpan.Zero))
                hasTwoForks = true;
            else
                PutFork(Left(i)); // ะ˜ะฝะพะณะดะฐ ะฟะปะพั…ะพะน ั„ะธะปะพัะพั„ ะพั‚ะดะฐะตั‚ ะฒะธะปะบัƒ ะฝะฐะทะฐะด.
        } 
        if (!hasTwoForks)
        {
            if (token.IsCancellationRequested) break;
            continue;
        }
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        bool goodPhilosopher = i % 2 == 0;
        // ะ ะฟะปะพั…ะพะน ั„ะธะปะพัะพั„ ะทะฐะฑั‹ะฒะฐะตั‚ ะฟะพะปะพะถะธั‚ัŒ ัะฒะพัŽ ะฒะธะปะบัƒ ะพะฑั€ะฐั‚ะฝะพ:
        if (goodPhilosopher)
            PutFork(Left(i));
        // ะ ะตัะปะธ ะธ ะฟั€ะฐะฒัƒัŽ ะฝะต ะฟะพะปะพะถะธั‚, ั‚ะพ ั…ะพั€ะพัˆะธะต ะฑัƒะดัƒั‚ ะฒะพะพะฑั‰ะต ะฑะตะท ะตะดั‹.
        PutFork(Right(i));

        Think(i);

        if (token.IsCancellationRequested)
            break;
    }
}

// ะขะตะฟะตั€ัŒ ะผะพะถะฝะพ ะถะดะฐั‚ัŒ ะพะฟั€ะตะดะตะปะตะฝะฝะพะต ะฒั€ะตะผั.
bool TakeFork(int fork, int philosopher, TimeSpan? waitTime = null)
{
    return SpinWait.SpinUntil(
        () => Interlocked.CompareExchange(ref forks[fork], philosopher, 0) == 0,
              waitTime ?? TimeSpan.FromMilliseconds(-1)
    );
}

ื”ื“ื‘ืจ ื”ื—ืฉื•ื‘ ื‘ืงื•ื“ ื”ื–ื” ื”ื•ื ืฉืฉื ื™ื™ื ืžืชื•ืš ืืจื‘ืขื” ืคื™ืœื•ืกื•ืคื™ื ืฉื•ื›ื—ื™ื ืœื”ื ื™ื— ืืช ื”ืžื–ืœื’ ื”ืฉืžืืœื™. ื•ืžืกืชื‘ืจ ืฉื”ื ืื•ื›ืœื™ื ื™ื•ืชืจ ืื•ื›ืœ, ื‘ืขื•ื“ ืฉืื—ืจื™ื ืžืชื—ื™ืœื™ื ืœื’ื•ื•ืข ื‘ืจืขื‘, ืœืžืจื•ืช ืฉืœื—ื•ื˜ื™ื ื™ืฉ ืื•ืชื” ืขื“ื™ืคื•ืช. ื›ืืŸ ื”ื ืœื ืœื’ืžืจื™ ืจืขื‘ื™ื, ื›ื™. ืคื™ืœื•ืกื•ืคื™ื ืจืขื™ื ืžื—ื–ื™ืจื™ื ืœืคืขืžื™ื ืืช ืžื–ืœื’ื™ื”ื ืœืื—ื•ืจ. ืžืกืชื‘ืจ ืฉืื ืฉื™ื ื˜ื•ื‘ื™ื ืื•ื›ืœื™ื ื‘ืขืจืš ืคื™ 5 ืคื—ื•ืช ืžืื ืฉื™ื ืจืขื™ื. ืื– ืฉื’ื™ืื” ืงื˜ื ื” ื‘ืงื•ื“ ืžื•ื‘ื™ืœื” ืœื™ืจื™ื“ื” ื‘ื‘ื™ืฆื•ืขื™ื. ื›ื“ืื™ ื’ื ืœืฆื™ื™ืŸ ื›ืืŸ ืฉื™ื™ืชื›ืŸ ืžืฆื‘ ื ื“ื™ืจ ืฉื‘ื• ื›ืœ ื”ืคื™ืœื•ืกื•ืคื™ื ืœื•ืงื—ื™ื ืืช ื”ืžื–ืœื’ ื”ืฉืžืืœื™, ืื™ืŸ ื™ืžื ื™, ืฉืžื™ื ืืช ื”ืฉืžืืœื™, ืžื—ื›ื™ื, ืœื•ืงื—ื™ื ืฉื•ื‘ ืฉืžืืœื” ื•ื›ื•'. ื”ืžืฆื‘ ื”ื–ื” ื”ื•ื ื’ื ืจืขื‘, ื™ื•ืชืจ ื›ืžื• ืžื‘ื•ื™ ืกืชื•ื. ืœื ื”ืฆืœื—ืชื™ ืœื—ื–ื•ืจ ืขืœ ื–ื”. ืœื”ืœืŸ ืชืžื•ื ื” ืœืžืฆื‘ ืฉื‘ื• ืฉื ื™ ืคื™ืœื•ืกื•ืคื™ื ืจืขื™ื ืœืงื—ื• ืืช ืฉื ื™ ื”ืžื–ืœื’ื•ืช ื•ืฉื ื™ื™ื ื˜ื•ื‘ื™ื ื’ื•ื•ืขื™ื ื‘ืจืขื‘.

ืคื™ืœื•ืกื•ืคื™ื ืžืื›ื™ืœื™ื ื”ื™ื˜ื‘ ืื• ืชื›ื ื•ืช NET ืชื—ืจื•ืชื™

ื›ืืŸ ืืชื” ื™ื›ื•ืœ ืœืจืื•ืช ืฉื”ืฉืจืฉื•ืจื™ื ืžืชืขื•ืจืจื™ื ืœืคืขืžื™ื ื•ืžื ืกื™ื ืœื”ืฉื™ื’ ืืช ื”ืžืฉืื‘. ืฉืชื™ื™ื ืžืืจื‘ืข ื”ืœื™ื‘ื•ืช ืœื ืขื•ืฉื•ืช ื›ืœื•ื (ื’ืจืฃ ื™ืจื•ืง ืœืžืขืœื”).

ืžื•ืชื• ืฉืœ ืคื™ืœื•ืกื•ืฃ

ื•ื‘ื›ืŸ, ื‘ืขื™ื” ื ื•ืกืคืช ืฉื™ื›ื•ืœื” ืœื”ืคืจื™ืข ืœืืจื•ื—ืช ืขืจื‘ ืžืคื•ืืจืช ืฉืœ ืคื™ืœื•ืกื•ืคื™ื ื”ื™ื ืื ืื—ื“ ืžื”ื ื™ืžื•ืช ืคืชืื•ื ืขื ืžื–ืœื’ื•ืช ื‘ื™ื“ื™ื• (ื•ื”ื ื™ืงื‘ืจื• ืื•ืชื• ื›ืš). ื•ืื– ื”ืฉื›ื ื™ื ื™ื™ืฉืืจื• ื‘ืœื™ ืืจื•ื—ืช ืฆื”ืจื™ื™ื. ืืชื” ื™ื›ื•ืœ ืœื”ืžืฆื™ื ืงื•ื“ ืœื“ื•ื’ืžื” ืœืžืงืจื” ื”ื–ื” ื‘ืขืฆืžืš, ืœืžืฉืœ, ื”ื•ื ื ื–ืจืง NullReferenceException ืื—ืจื™ ืฉื”ืคื™ืœื•ืกื•ืฃ ืœื•ืงื— ืืช ื”ืžื–ืœื’ื•ืช. ื•ื“ืจืš ืื’ื‘, ื”ื—ืจื™ื’ ืœื ื™ื˜ื•ืคืœ ื•ื”ืงื•ื“ ื”ืžืชืงืฉืจ ืœื ืจืง ื™ืชืคื•ืก ืื•ืชื• (ื‘ืฉื‘ื™ืœ ื–ื” AppDomain.CurrentDomain.UnhandledException ื•ื›ื•.). ืœื›ืŸ, ื“ืจื•ืฉื™ื ืžื˜ืคืœื™ ืฉื’ื™ืื•ืช ื‘ืฉืจืฉื•ืจื™ื ืขืฆืžื ื•ื‘ืกื™ื•ื ื—ื™ื ื ื™.

ืžืœืฆืจ

ืื•ืงื™ื™, ืื™ืš ืคื•ืชืจื™ื ืืช ื‘ืขื™ื™ืช ื”ืงื™ืคืื•ืŸ, ื”ืจืขื‘ ื•ื”ืžื•ื•ืช? ื ืืคืฉืจ ืจืง ืœืคื™ืœื•ืกื•ืฃ ืื—ื“ ืœื”ื’ื™ืข ืœืžื–ืœื’ื•ืช, ื ื•ืกื™ืฃ ืื™ ื”ื›ืœืœื” ื”ื“ื“ื™ืช ืฉืœ ื—ื•ื˜ื™ื ืœืžืงื•ื ื”ื–ื”. ืื™ืš ืœืขืฉื•ืช ืืช ื–ื”? ื ื ื™ื— ืฉืžืœืฆืจ ืขื•ืžื“ ืœื™ื“ ื”ืคื™ืœื•ืกื•ืคื™ื, ืฉื ื•ืชืŸ ืจืฉื•ืช ืœื›ืœ ืคื™ืœื•ืกื•ืฃ ืื—ื“ ืœืงื—ืช ืืช ื”ืžื–ืœื’ื™ื. ืื™ืš ื ื›ื™ืŸ ืืช ื”ืžืœืฆืจ ื”ื–ื” ื•ืื™ืš ื™ืฉืืœื• ืื•ืชื• ืคื™ืœื•ืกื•ืคื™ื, ื”ืฉืืœื•ืช ืžืขื ื™ื™ื ื•ืช.

ื”ื“ืจืš ื”ืคืฉื•ื˜ื” ื‘ื™ื•ืชืจ ื”ื™ื ื›ืฉื”ืคื™ืœื•ืกื•ืคื™ื ืคืฉื•ื˜ ื™ื‘ืงืฉื• ื›ืœ ื”ื–ืžืŸ ืžื”ืžืœืฆืจ ื’ื™ืฉื” ืœืžื–ืœื’ื•ืช. ื”ึธื”ึตืŸ. ืขื›ืฉื™ื• ืคื™ืœื•ืกื•ืคื™ื ืœื ื™ื—ื›ื• ืœืžื–ืœื’ ื‘ืงืจื‘ืช ืžืงื•ื, ืืœื ื™ืžืชื™ื ื• ืื• ื™ืฉืืœื• ืืช ื”ืžืœืฆืจ. ื‘ื”ืชื—ืœื”, ืื ื—ื ื• ืžืฉืชืžืฉื™ื ืจืง ื‘-User Space ื‘ืฉื‘ื™ืœ ื–ื”, ื‘ื• ืื ื—ื ื• ืœื ืžืฉืชืžืฉื™ื ื‘ืคืกื™ืงื•ืช ื›ื“ื™ ืœืงืจื•ื ืœืคืจื•ืฆื“ื•ืจื•ืช ื›ืœืฉื”ืŸ ืžื”ืงืจื ืœ (ืขืœื™ื”ื ืœืžื˜ื”).

ืคืชืจื•ื ื•ืช ื‘ืžืจื—ื‘ ื”ืžืฉืชืžืฉ

ื›ืืŸ ื ืขืฉื” ื›ืžื• ืฉื ื”ื’ื ื• ืœืขืฉื•ืช ืขื ืžื–ืœื’ ืื—ื“ ื•ืฉื ื™ ืคื™ืœื•ืกื•ืคื™ื, ื ืกื•ื‘ื‘ ื‘ืžื—ื–ื•ืจ ื•ื ืžืชื™ืŸ. ืื‘ืœ ืขื›ืฉื™ื• ื–ื” ื™ื”ื™ื” ื”ื›ืœ ืคื™ืœื•ืกื•ืคื™ื ื•ื›ืื™ืœื• ืจืง ืžื–ืœื’ ืื—ื“, ื›ืœื•ืžืจ. ืืคืฉืจ ืœื•ืžืจ ืฉืจืง ื”ืคื™ืœื•ืกื•ืฃ ืฉืœืงื— ืืช "ืžื–ืœื’ ื”ื–ื”ื‘" ื”ื–ื” ืžื”ืžืœืฆืจ ื™ืื›ืœ. ืœืฉื ื›ืš ืื ื• ืžืฉืชืžืฉื™ื ื‘- SpinLock.

private static SpinLock spinLock = new SpinLock();  // ะะฐัˆ "ะพั„ะธั†ะธะฐะฝั‚"
private void RunSpinLock(int i, CancellationToken token)
{
    while (true)
    {
        // ะ’ะทะฐะธะผะฝะฐั ะฑะปะพะบะธั€ะพะฒะบะฐ ั‡ะตั€ะตะท busy waiting. ะ’ั‹ะทั‹ะฒะฐะตะผ ะดะพ try, ั‡ั‚ะพะฑั‹
        // ะฒั‹ะฑั€ะฐัะธั‚ัŒ ะธัะบะปัŽั‡ะตะฝะธะต ะฒ ัะปัƒั‡ะฐะต ะพัˆะธะฑะบะธ ะฒ ัะฐะผะพะผ SpinLock.
        bool hasLock = false;
        spinLock.Enter(ref hasLock);
        try
        {
            // ะ—ะดะตััŒ ะผะพะถะตั‚ ะฑั‹ั‚ัŒ ั‚ะพะปัŒะบะพ ะพะดะธะฝ ะฟะพั‚ะพะบ (mutual exclusion).
            forks[Left(i)] = i + 1;  // ะ‘ะตั€ะตะผ ะฒะธะปะบัƒ ัั€ะฐะทัƒ, ะฑะตะท ะพะถะธะดะฐะฝะธั.
            forks[Right(i)] = i + 1;
            eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
            forks[Left(i)] = 0;
            forks[Right(i)] = 0;
        }
        finally
        {
            if(hasLock) spinLock.Exit();  // ะ˜ะทะฑะตะณะฐะตะผ ะฟั€ะพะฑะปะตะผั‹ ัะพ ัะผะตั€ั‚ัŒัŽ ั„ะธะปะพัะพั„ะฐ.
        }

        Think(i);

        if (token.IsCancellationRequested)
            break;
    }
}

SpinLock ื–ื” ื—ื•ืกื, ืขื, ื‘ืขืจืš, ืื•ืชื• ื“ื‘ืจ while(true) { if (!lock) break; }, ืื‘ืœ ืขื ืืคื™ืœื• ื™ื•ืชืจ "ืงืกื" ืžืืฉืจ ื‘ SpinWait (ืฉืžืฉืชืžืฉื™ื ื‘ื• ืฉื). ืขื›ืฉื™ื• ื”ื•ื ื™ื•ื“ืข ืœืกืคื•ืจ ืืช ื”ืžืžืชื™ื ื™ื, ืœื”ืจื“ื™ื ืื•ืชื ืงืฆืช ื•ืขื•ื“. ื•ื›ื•' ื‘ืื•ืคืŸ ื›ืœืœื™, ืขื•ืฉื” ื”ื›ืœ ื›ื“ื™ ืœื™ื™ืขืœ. ืื‘ืœ ืขืœื™ื ื• ืœื–ื›ื•ืจ ืฉื–ื”ื• ืขื“ื™ื™ืŸ ืื•ืชื• ืžื—ื–ื•ืจ ืืงื˜ื™ื‘ื™ ืฉืื•ื›ืœ ืืช ืžืฉืื‘ื™ ื”ืžืขื‘ื“ ื•ืฉื•ืžืจ ืขืœ ื”ื–ืจื™ืžื”, ืžื” ืฉืขืœื•ืœ ืœื”ื•ื‘ื™ืœ ืœืจืขื‘ ืื ืื—ื“ ืžื”ืคื™ืœื•ืกื•ืคื™ื ื™ืงื‘ืœ ืขื“ื™ืคื•ืช ื™ื•ืชืจ ืžืื—ืจื™ื, ืื‘ืœ ืื™ืŸ ืœื• ืžื–ืœื’ ืžื•ื–ื”ื‘ (ื‘ืขื™ื™ืช ืคืจื™ื•ืจื™ื˜ื™ ื”ื™ืคื•ืš) . ืœื›ืŸ, ืื ื• ืžืฉืชืžืฉื™ื ื‘ื• ืจืง ืœืฉื™ื ื•ื™ื™ื ืงืฆืจื™ื ืžืื•ื“ ื‘ื–ื™ื›ืจื•ืŸ ื”ืžืฉื•ืชืฃ, ืœืœื ืฉื™ื—ื•ืช ืฉืœ ืฆื“ ืฉืœื™ืฉื™, ืžื ืขื•ืœื™ื ืžืงื•ื ื ื™ื ื•ื”ืคืชืขื•ืช ืื—ืจื•ืช.

ืคื™ืœื•ืกื•ืคื™ื ืžืื›ื™ืœื™ื ื”ื™ื˜ื‘ ืื• ืชื›ื ื•ืช NET ืชื—ืจื•ืชื™

ืฆื™ื•ืจ ืขื‘ื•ืจ SpinLock. ื”ื ื—ืœื™ื "ื ืœื—ืžื™ื" ืœืœื ื”ืจืฃ ืขืœ ืžื–ืœื’ ื”ื–ื”ื‘. ื™ืฉ ื›ืฉืœื™ื - ื‘ืื™ื•ืจ, ื”ืื–ื•ืจ ื”ื ื‘ื—ืจ. ื”ืœื™ื‘ื•ืช ืื™ื ืŸ ืžื ื•ืฆืœื•ืช ื‘ืžืœื•ืืŸ: ืจืง ื›-2/3 ืขืœ ื™ื“ื™ ืืจื‘ืขืช ื”ื—ื•ื˜ื™ื ื”ืœืœื•.

ืคืชืจื•ืŸ ื ื•ืกืฃ ื›ืืŸ ื™ื”ื™ื” ืœื”ืฉืชืžืฉ ื‘ืœื‘ื“ Interlocked.CompareExchange ืขื ืื•ืชื” ื”ืžืชื ื” ืคืขื™ืœื” ื›ืคื™ ืฉืžื•ืฆื’ ื‘ืงื•ื“ ืœืžืขืœื” (ืืฆืœ ื”ืคื™ืœื•ืกื•ืคื™ื ื”ืžื•ืจืขื‘ื™ื), ืื‘ืœ ื–ื”, ื›ืคื™ ืฉื›ื‘ืจ ื ืืžืจ, ื™ื›ื•ืœ ืœื”ื•ื‘ื™ืœ ืชื™ืื•ืจื˜ื™ืช ืœื—ืกื™ืžื”.

ืขืœ Interlocked ื™ืฉ ืœืฆื™ื™ืŸ ืฉืื™ืŸ ืจืง CompareExchange, ืื‘ืœ ื’ื ืฉื™ื˜ื•ืช ืื—ืจื•ืช ืœืงืจื™ืื” ื•ื›ืชื™ื‘ื” ืื˜ื•ืžื™ืช. ื•ื‘ืืžืฆืขื•ืช ื”ื—ื–ืจื” ืขืœ ื”ืฉื™ื ื•ื™, ื‘ืžืงืจื” ืฉืœ ืฉืจืฉื•ืจ ืื—ืจ ื™ืฉ ื–ืžืŸ ืœื‘ืฆืข ืืช ื”ืฉื™ื ื•ื™ื™ื ืฉืœื• (ืœืงืจื•ื 1, ืœืงืจื•ื 2, ืœื›ืชื•ื‘ 2, ืœื›ืชื•ื‘ 1 ื–ื” ืจืข), ื ื™ืชืŸ ืœื”ืฉืชืžืฉ ื‘ื• ืœืฉื™ื ื•ื™ื™ื ืžื•ืจื›ื‘ื™ื ืœืขืจืš ื‘ื•ื“ื“ (ื“ืคื•ืก Interlocked Anything) .

ืคืชืจื•ื ื•ืช ืžืฆื‘ ืœื™ื‘ื”

ื›ื“ื™ ืœื”ื™ืžื ืข ืžื‘ื–ื‘ื•ื– ืžืฉืื‘ื™ื ื‘ืœื•ืœืื”, ื‘ื•ืื• ื ืจืื” ื›ื™ืฆื“ ื ื•ื›ืœ ืœื—ืกื•ื ืฉืจืฉื•ืจ. ื‘ืžื™ืœื™ื ืื—ืจื•ืช, ื‘ื”ืžืฉืš ื”ื“ื•ื’ืžื” ืฉืœื ื•, ื‘ื•ืื• ื ืจืื” ืื™ืš ื”ืžืœืฆืจ ืžืจื“ื™ื ืืช ื”ืคื™ืœื•ืกื•ืฃ ื•ืžืขื™ืจ ืื•ืชื• ืจืง ื›ืฉืฆืจื™ืš. ืจืืฉื™ืช, ื‘ื•ืื• ื ืกืชื›ืœ ื›ื™ืฆื“ ืœืขืฉื•ืช ื–ืืช ื“ืจืš ืžืฆื‘ ื”ืœื™ื‘ื” ืฉืœ ืžืขืจื›ืช ื”ื”ืคืขืœื”. ื›ืœ ื”ืžื‘ื ื™ื ืฉื ืœืจื•ื‘ ืื™ื˜ื™ื™ื ื™ื•ืชืจ ืžืืœื” ืฉื‘ืžืจื—ื‘ ื”ืžืฉืชืžืฉ. ืื™ื˜ื™ ืคื™ ื›ืžื”, ืœืžืฉืœ AutoResetEvent ืื•ืœื™ ืคื™ 53 ืœืื˜ ื™ื•ืชืจ SpinLock [ืจื™ื›ื˜ืจ]. ืื‘ืœ ื‘ืขื–ืจืชื ืชื•ื›ืœื• ืœืกื ื›ืจืŸ ืชื”ืœื™ื›ื™ื ื‘ื›ืœ ื”ืžืขืจื›ืช, ืžื ื•ื”ืœื™ื ืื• ืœื.

ื”ืžื‘ื ื” ื”ื‘ืกื™ืกื™ ื›ืืŸ ื”ื•ื ื”ืกืžืคื•ืจ ืฉื”ืฆื™ืข ื“ื™ืงืกื˜ืจื” ืœืคื ื™ ืœืžืขืœื” ืžื—ืฆื™ ืžืื”. ืกืžืคื•ืจ ื”ื•ื, ื‘ืžื™ืœื™ื ืคืฉื•ื˜ื•ืช, ืžืกืคืจ ืฉืœื ื—ื™ื•ื‘ื™ ื”ืžื ื•ื”ืœ ืขืœ ื™ื“ื™ ื”ืžืขืจื›ืช, ื•ืฉืชื™ ืคืขื•ืœื•ืช ืขืœื™ื•, ื”ื’ื“ืœื” ื•ื”ืงื˜ื ื”. ืื ื–ื” ืœื ื™ืฆืœื™ื— ืœืจื“ืช, ืืคืก, ืื– ื—ื•ื˜ ื”ืงื•ืจื ื ื—ืกื. ื›ืืฉืจ ื”ืžืกืคืจ ืžื•ื’ื“ืœ ืขืœ ื™ื“ื™ ื—ื•ื˜/ืชื”ืœื™ืš ืคืขื™ืœ ืื—ืจ, ื”ื“ื™ืœื•ื’ื™ื ืขืœ ื”ืฉืจืฉื•ืจื™ื ื•ื”ืกืžืคื•ืจ ืžื•ืคื—ืช ืฉื•ื‘ ื‘ืžืกืคืจ ืฉืขื‘ืจ. ืืคืฉืจ ืœื“ืžื™ื™ืŸ ืจื›ื‘ื•ืช ื‘ืฆื•ื•ืืจ ื‘ืงื‘ื•ืง ืขื ืกืžืคื•ืจ. NET ืžืฆื™ืขื” ืžืกืคืจ ืžื‘ื ื™ื ืขื ืคื•ื ืงืฆื™ื•ื ืœื™ื•ืช ื“ื•ืžื”: AutoResetEvent, ManualResetEvent, Mutex ื•ืืช ืขืฆืžื™ Semaphore. ืื ื—ื ื• ื ืฉืชืžืฉ AutoResetEvent, ื–ื”ื• ื”ืงื•ื ืกื˜ืจื•ืงืฆื™ื” ื”ืคืฉื•ื˜ื” ื‘ื™ื•ืชืจ: ืจืง ืฉื ื™ ืขืจื›ื™ื 0 ื•-1 (ืฉืงืจ, ื ื›ื•ืŸ). ื”ืฉื™ื˜ื” ืฉืœื” WaitOne() ื—ื•ืกื ืืช ื”ืฉืจืฉื•ืจ ื”ืงื•ืจื ืื ื”ืขืจืš ื”ื™ื” 0, ื•ืื 1, ืžื•ืจื™ื“ ืื•ืชื• ืœ-0 ื•ืžื“ืœื’ ืขืœื™ื•. ืฉื™ื˜ื” Set() ืžืขืœื” ืœ-1 ื•ื ื•ืชืŸ ืœืžืœืฆืจ ืื—ื“ ืœืขื‘ื•ืจ, ืฉืฉื•ื‘ ืžื•ืจื™ื“ ืœ-0. ืžืชื ื”ื’ ื›ืžื• ืงืจื•ืกืœืช ืจื›ื‘ืช ืชื—ืชื™ืช.

ื‘ื•ืื• ื ืกื‘ืš ืืช ื”ืคืชืจื•ืŸ ื•ื ืฉืชืžืฉ ื‘ืžื ืขื•ืœ ืขื‘ื•ืจ ื›ืœ ืคื™ืœื•ืกื•ืฃ, ื•ืœื ื‘ื‘ืช ืื—ืช. ื”ึธื”ึตืŸ. ืขื›ืฉื™ื• ื™ื›ื•ืœื™ื ืœื”ื™ื•ืช ื›ืžื” ืคื™ืœื•ืกื•ืคื™ื ื‘ื• ื–ืžื ื™ืช, ื•ืœื ืื—ื“. ืื‘ืœ ืื ื—ื ื• ืฉื•ื‘ ื—ื•ืกืžื™ื ืืช ื”ื’ื™ืฉื” ืœื˜ื‘ืœื” ืขืœ ืžื ืช ืœื”ื™ืžื ืข ื ื›ื•ืŸ ืžืžื™ืจื•ืฆื™ื (ืชื ืื™ ืžื™ืจื•ืฅ), ืœืงื—ืช ื”ื™ืžื•ืจื™ื ื‘ื˜ื•ื—ื™ื.

// ะ”ะปั ะฑะปะพะบะธั€ะพะฒะฐะฝะธั ะพั‚ะดะตะปัŒะฝะพะณะพ ั„ะธะปะพัะพั„ะฐ.
// ะ˜ะฝะธั†ะธะฐะปะธะทะธั€ัƒะตั‚ัั: new AutoResetEvent(true) ะดะปั ะบะฐะถะดะพะณะพ.
private AutoResetEvent[] philosopherEvents;

// ะ”ะปั ะดะพัั‚ัƒะฟะฐ ะบ ะฒะธะปะบะฐะผ / ะดะพัั‚ัƒะฟ ะบ ัั‚ะพะปัƒ.
private AutoResetEvent tableEvent = new AutoResetEvent(true);

// ะ ะพะถะดะตะฝะธะต ั„ะธะปะพัะพั„ะฐ.
public void Run(int i, CancellationToken token)
{
    while (true)
    {
        TakeForks(i); // ะ–ะดะตั‚ ะฒะธะปะบะธ.
        // ะžะฑะตะด. ะœะพะถะตั‚ ะฑั‹ั‚ัŒ ะธ ะดะพะปัŒัˆะต.
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        PutForks(i); // ะžั‚ะดะฐั‚ัŒ ะฒะธะปะบะธ ะธ ั€ะฐะทะฑะปะพะบะธั€ะพะฒะฐั‚ัŒ ัะพัะตะดะตะน.
        Think(i);
        if (token.IsCancellationRequested) break;
    }
}

// ะžะถะธะดะฐั‚ัŒ ะฒะธะปะบะธ ะฒ ะฑะปะพะบะธั€ะพะฒะบะต.
void TakeForks(int i)
{
    bool hasForks = false;
    while (!hasForks) // ะŸะพะฟั€ะพะฑะพะฒะฐั‚ัŒ ะตั‰ะต ั€ะฐะท (ะฑะปะพะบะธั€ะพะฒะบะฐ ะฝะต ะทะดะตััŒ).
    {
        // ะ˜ัะบะปัŽั‡ะฐัŽั‰ะธะน ะดะพัั‚ัƒะฟ ะบ ัั‚ะพะปัƒ, ะฑะตะท ะณะพะฝะพะบ ะทะฐ ะฒะธะปะบะฐะผะธ.
        tableEvent.WaitOne();
        if (forks[Left(i)] == 0 && forks[Right(i)] == 0)
            forks[Left(i)] = forks[Right(i)] = i + 1;
        hasForks = forks[Left(i)] == i + 1 && forks[Right(i)] == i + 1;
        if (hasForks)
            // ะขะตะฟะตั€ัŒ ั„ะธะปะพัะพั„ ะฟะพะตัั‚, ะฒั‹ะนะดะตั‚ ะธะท ั†ะธะบะปะฐ. ะ•ัะปะธ Set 
            // ะฒั‹ะทะฒะฐะฝ ะดะฒะฐะถะดั‹, ั‚ะพ ะทะฝะฐั‡ะตะฝะธะต true.
            philosopherEvents[i].Set();
        // ะ ะฐะทะฑะปะพะบะธั€ะพะฒะฐั‚ัŒ ะพะดะฝะพะณะพ ะพะถะธะดะฐัŽั‰ะตะณะพ. ะŸะพัะปะต ะฝะตะณะพ ะทะฝะฐั‡ะตะฝะธะต tableEvent ะฒ false.
        tableEvent.Set(); 
        // ะ•ัะปะธ ะธะผะตะตั‚ true, ะฝะต ะฑะปะพะบะธั€ัƒะตั‚ัั, ะฐ ะตัะปะธ false, ั‚ะพ ะฑัƒะดะตั‚ ะถะดะฐั‚ัŒ Set ะพั‚ ัะพัะตะดะฐ.
        philosopherEvents[i].WaitOne();
    }
}

// ะžั‚ะดะฐั‚ัŒ ะฒะธะปะบะธ ะธ ั€ะฐะทะฑะปะพะบะธั€ะพะฒะฐั‚ัŒ ัะพัะตะดะตะน.
void PutForks(int i)
{
    tableEvent.WaitOne(); // ะ‘ะตะท ะณะพะฝะพะบ ะทะฐ ะฒะธะปะบะฐะผะธ.
    forks[Left(i)] = 0;
    // ะŸั€ะพะฑัƒะดะธั‚ัŒ ะปะตะฒะพะณะพ, ะฐ ะฟะพั‚ะพะผ ะธ ะฟั€ะฐะฒะพะณะพ ัะพัะตะดะฐ, ะปะธะฑะพ AutoResetEvent ะฒ true.
    philosopherEvents[LeftPhilosopher(i)].Set();
    forks[Right(i)] = 0;
    philosopherEvents[RightPhilosopher(i)].Set();
    tableEvent.Set();
}

ื›ื“ื™ ืœื”ื‘ื™ืŸ ืžื” ืงื•ืจื” ื›ืืŸ, ืฉืงื•ืœ ืืช ื”ืžืงืจื” ืฉื‘ื• ื”ืคื™ืœื•ืกื•ืฃ ืœื ื”ืฆืœื™ื— ืœืงื—ืช ืืช ื”ืžื–ืœื’ื•ืช, ืื– ืžืขืฉื™ื• ื™ื”ื™ื• ื›ื“ืœืงืžืŸ. ื”ื•ื ืžื—ื›ื” ืœื’ื™ืฉื” ืœืฉื•ืœื—ืŸ. ืœืื—ืจ ืฉืงื™ื‘ืœ ืื•ืชื•, ื”ื•ื ืžื ืกื” ืœืงื—ืช ืืช ื”ืžื–ืœื’ื™ื. ืœื ื”ืกืชื“ืจ. ื–ื” ื ื•ืชืŸ ื’ื™ืฉื” ืœื˜ื‘ืœื” (ืื™ ื”ื›ืœืœื” ื”ื“ื“ื™ืช). ื•ืขื•ื‘ืจ ืืช ื”"ืงืจื•ืกืœื”" ืฉืœื• (AutoResetEvent) (ื”ื ืคืชื•ื—ื™ื ื‘ื”ืชื—ืœื”). ื–ื” ื ื›ื ืก ืฉื•ื‘ ืœืžื—ื–ื•ืจ, ื›ื™ ืื™ืŸ ืœื• ืžื–ืœื’ื•ืช. ื”ื•ื ืžื ืกื” ืœืงื—ืช ืื•ืชื ื•ืขื•ืฆืจ ืœื™ื“ ื”"ืงืจื•ืกืœื”" ืฉืœื•. ืื™ื–ื” ืฉื›ืŸ ื‘ืจ ืžื–ืœ ื™ื•ืชืจ ืžื™ืžื™ืŸ ืื• ืฉืžืืœ, ืœืื—ืจ ืฉืกื™ื™ื ืœืื›ื•ืœ, ืคื•ืชื— ืืช ื”ืคื™ืœื•ืกื•ืฃ ืฉืœื ื•, "ืคื•ืชื— ืืช ื”ืงืจื•ืกืœื” ืฉืœื•". ื”ืคื™ืœื•ืกื•ืฃ ืฉืœื ื• ืžืขื‘ื™ืจ ืื•ืชื• (ื•ื”ื•ื ื ืกื’ืจ ืžืื—ื•ืจื™ื•) ื‘ืคืขื ื”ืฉื ื™ื™ื”. ื”ื•ื ืžื ืกื” ื‘ืคืขื ื”ืฉืœื™ืฉื™ืช ืœืงื—ืช ืืช ื”ืžื–ืœื’ื™ื. ื‘ื”ืฆืœื—ื”. ื•ื”ื•ื ืžืขื‘ื™ืจ ืืช ื”ืงืจื•ืกืœื” ืฉืœื• ืœืกืขื•ื“.

ื›ืืฉืจ ื™ืฉ ืฉื’ื™ืื•ืช ืืงืจืื™ื•ืช ื‘ืงื•ื“ ื›ื–ื” (ื”ืŸ ืชืžื™ื“ ืงื™ื™ืžื•ืช), ืœืžืฉืœ, ืฉื›ื ื” ืฆื•ื™ืŸ ื‘ืฆื•ืจื” ืฉื’ื•ื™ื” ืื• ื ื•ืฆืจ ืื•ืชื• ืื•ื‘ื™ื™ืงื˜ AutoResetEvent ืœื›ื•ืœื (Enumerable.Repeat), ืื– ื”ืคื™ืœื•ืกื•ืคื™ื ื™ื—ื›ื• ืœืžืคืชื—ื™ื, ื›ื™ ืžืฆื™ืืช ืฉื’ื™ืื•ืช ื‘ืงื•ื“ ื›ื–ื” ื”ื™ื ืžืฉื™ืžื” ืงืฉื” ืœืžื“ื™. ื‘ืขื™ื” ื ื•ืกืคืช ืขื ื”ืคืชืจื•ืŸ ื”ื–ื” ื”ื™ื ืฉื”ื•ื ืœื ืžื‘ื˜ื™ื— ืฉืคื™ืœื•ืกื•ืฃ ื›ืœืฉื”ื• ืœื ื™ื’ื•ื•ืข ื‘ืจืขื‘.

ืคืชืจื•ื ื•ืช ื”ื™ื‘ืจื™ื“ื™ื™ื

ื‘ื“ืงื ื• ืฉืชื™ ื’ื™ืฉื•ืช ืœืชื–ืžื•ืŸ, ื›ืืฉืจ ืื ื• ื ืฉืืจื™ื ื‘ืžืฆื‘ ืžืฉืชืžืฉ ื•ืœื•ืœืื”, ื•ื›ืืฉืจ ืื ื• ื—ื•ืกืžื™ื ื—ื•ื˜ ื“ืจืš ื”ืœื™ื‘ื”. ื”ืฉื™ื˜ื” ื”ืจืืฉื•ื ื” ื˜ื•ื‘ื” ืœืžื ืขื•ืœื™ื ืงืฆืจื™ื, ื”ืฉื ื™ื™ื” ืœืืจื•ื›ื™ื. ืœืขืชื™ื ืงืจื•ื‘ื•ืช ื™ืฉ ืฆื•ืจืš ืœื”ืžืชื™ืŸ ืœื–ืžืŸ ืงืฆืจ ืขื“ ืฉื”ืžืฉืชื ื” ื™ืฉืชื ื” ื‘ืœื•ืœืื”, ื•ืœืื—ืจ ืžื›ืŸ ืœื—ืกื•ื ืืช ื”ืฉืจืฉื•ืจ ื›ืืฉืจ ื”ื”ืžืชื ื” ืืจื•ื›ื”. ื’ื™ืฉื” ื–ื• ืžื™ื•ืฉืžืช ื‘ืžื” ืฉื ืงืจื. ืžื‘ื ื™ื ื”ื™ื‘ืจื™ื“ื™ื™ื. ืœื”ืœืŸ ืื•ืชื ืžื‘ื ื™ื ื›ืžื• ืขื‘ื•ืจ ืžืฆื‘ ืœื™ื‘ื”, ืืš ื›ืขืช ืขื ืœื•ืœืืช ืžืฆื‘ ืžืฉืชืžืฉ: SemaphorSlim, ManualResetEventSlim ื•ื›ื•' ื”ืขื™ืฆื•ื‘ ื”ืคื•ืคื•ืœืจื™ ื‘ื™ื•ืชืจ ื›ืืŸ ื”ื•ื Monitor, ื›ื™ ื‘-C# ื™ืฉ ื™ื“ื•ืข lock ืชื—ื‘ื™ืจ. Monitor ื–ื”ื• ืื•ืชื• ืกืžืคื•ืจ ืขื ืขืจืš ืžืงืกื™ืžืœื™ ืฉืœ 1 (ืžื•ื˜ืงืก), ืื‘ืœ ืขื ืชืžื™ื›ื” ื‘ื”ืžืชื ื” ื‘ืœื•ืœืื”, ืจืงื•ืจืกื™ื”, ื“ืคื•ืก ื”-Condition Variable (ืขื•ื“ ืขืœ ื›ืš ื‘ื”ืžืฉืš) ื•ื›ื•'. ื‘ื•ืื• ื ืกืชื›ืœ ืื™ืชื• ืขืœ ืคืชืจื•ืŸ.

// ะกะฟั€ัั‡ะตะผ ะพะฑัŠะตะบั‚ ะดะปั ะœะพะฝะธั‚ะพั€ะฐ ะพั‚ ะฒัะตั…, ั‡ั‚ะพะฑั‹ ะฑะตะท ะดะตะดะปะพะบะพะฒ.
private readonly object _lock = new object();
// ะ’ั€ะตะผั ะพะถะธะดะฐะฝะธั ะฟะพั‚ะพะบะฐ.
private DateTime?[] _waitTimes = new DateTime?[philosophersAmount];

public void Run(int i, CancellationToken token)
{
    while (true)
    {
        TakeForks(i);
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        PutForks(i);
        Think(i);
        if (token.IsCancellationRequested) break;
    }
}

// ะะฐัˆะต ัะปะพะถะฝะพะต ัƒัะปะพะฒะธะต ะดะปั Condition Variable ะฟะฐั‚ั‚ะตั€ะฝะฐ.
bool CanIEat(int i)
{
    // ะ•ัะปะธ ะตัั‚ัŒ ะฒะธะปะบะธ:
    if (forks[Left(i)] != 0 && forks[Right(i)] != 0)
        return false;
    var now = DateTime.Now;
    // ะœะพะถะตั‚, ะตัะปะธ ัะพัะตะดะธ ะฝะต ะฑะพะปะตะต ะณะพะปะพะดะฝั‹ะต, ั‡ะตะผ ั‚ะตะบัƒั‰ะธะน.
    foreach(var p in new int[] {LeftPhilosopher(i), RightPhilosopher(i)})
        if (_waitTimes[p] != null && now - _waitTimes[p] > now - _waitTimes[i])
            return false;
    return true;
}

void TakeForks(int i)
{
    // ะ—ะฐะนั‚ะธ ะฒ ะœะพะฝะธั‚ะพั€. ะขะพ ะถะต ัะฐะผะพะต: lock(_lock) {..}.
    // ะ’ั‹ะทั‹ะฒะฐะตะผ ะฒะฝะต try, ั‡ั‚ะพะฑั‹ ะฒะพะทะผะพะถะฝะพะต ะธัะบะปัŽั‡ะตะฝะธะต ะฒั‹ะฑั€ะฐัั‹ะฒะฐะปะพััŒ ะฒั‹ัˆะต.
    bool lockTaken = false;
    Monitor.Enter(_lock, ref lockTaken);
    try
    {
        _waitTimes[i] = DateTime.Now;
        // Condition Variable ะฟะฐั‚ั‚ะตั€ะฝ. ะžัะฒะพะฑะพะถะดะฐะตะผ ะปะพะบ, ะตัะปะธ ะฝะต ะฒั‹ะฟะพะปะฝะตะฝะฝะพ 
        // ัะปะพะถะฝะพะต ัƒัะปะพะฒะธะต. ะ˜ ะถะดะตะผ ะฟะพะบะฐ ะบั‚ะพ-ะฝะธะฑัƒะดัŒ ัะดะตะปะฐะตั‚ Pulse / PulseAll.
        while (!CanIEat(i))
            Monitor.Wait(_lock); 
        forks[Left(i)] = i + 1;
        forks[Right(i)] = i + 1;
        _waitTimes[i] = null;
    }
    finally
    {
        if (lockTaken) Monitor.Exit(_lock);
    }
}

void PutForks(int i)
{
    // ะขะพ ะถะต ัะฐะผะพะต: lock (_lock) {..}.
    bool lockTaken = false;
    Monitor.Enter(_lock, ref lockTaken);
    try
    {
        forks[Left(i)] = 0;
        forks[Right(i)] = 0;
        // ะžัะฒะพะฑะพะดะธั‚ัŒ ะฒัะต ะฟะพั‚ะพะบะธ ะฒ ะพั‡ะตั€ะตะดะธ ะŸะžะกะ›ะ• ะฒั‹ะทะพะฒะฐ Monitor.Exit.
        Monitor.PulseAll(_lock); 
    }
    finally
    {
        if (lockTaken) Monitor.Exit(_lock);
    }
}

ื›ืืŸ ืื ื—ื ื• ืฉื•ื‘ ื—ื•ืกืžื™ื ืืช ื›ืœ ื”ืฉื•ืœื—ืŸ ืœื’ื™ืฉื” ืœืžื–ืœื’ื•ืช, ืื‘ืœ ืขื›ืฉื™ื• ืื ื—ื ื• ื—ื•ืกืžื™ื ืืช ื›ืœ ื”ื—ื•ื˜ื™ื ื‘ื‘ืช ืื—ืช, ื•ืœื ืฉื›ื ื™ื ื›ืฉืžื™ืฉื”ื• ืžืกื™ื™ื ืœืื›ื•ืœ. ื”ึธื”ึตืŸ. ืจืืฉื™ืช, ืžื™ืฉื”ื• ืื•ื›ืœ ื•ื—ื•ืกื ืืช ื”ืฉื›ื ื™ื, ื•ื›ืืฉืจ ืžื™ืฉื”ื• ื–ื” ืžืกื™ื™ื, ืื‘ืœ ืจื•ืฆื” ืœืื›ื•ืœ ืฉื•ื‘ ืžื™ื“, ื”ื•ื ื ื›ื ืก ืœื—ืกื™ืžื” ื•ืžืขื™ืจ ืืช ื”ืฉื›ื ื™ื ืฉืœื•, ื›ื™. ื–ืžืŸ ื”ื”ืžืชื ื” ืฉืœื• ืงื˜ืŸ ื™ื•ืชืจ.

ื›ืš ื ืžื ืขื™ื ืžืžื‘ื•ื™ ืกืชื•ื ื•ืžืจืขื‘ ืฉืœ ืื™ื–ื” ืคื™ืœื•ืกื•ืฃ. ืื ื• ืžืฉืชืžืฉื™ื ื‘ืœื•ืœืื” ืœื”ืžืชื ื” ืงืฆืจื” ื•ื—ื•ืกืžื™ื ืืช ื”ื—ื•ื˜ ืœื–ืžืŸ ืืจื•ืš. ื‘ื™ื˜ื•ืœ ื”ื—ืกื™ืžื” ืฉืœ ื›ื•ืœื ื‘ื‘ืช ืื—ืช ื”ื•ื ืื™ื˜ื™ ื™ื•ืชืจ ืžืืฉืจ ืื ืจืง ื”ืฉื›ืŸ ื”ื™ื” ื‘ื•ื˜ื—, ื›ืžื• ื‘ืคืชืจื•ืŸ ืขื AutoResetEvent, ืื‘ืœ ื”ื”ื‘ื“ืœ ืœื ืฆืจื™ืš ืœื”ื™ื•ืช ื’ื“ื•ืœ, ื›ื™ ื”ืืฉื›ื•ืœื•ืช ื—ื™ื™ื‘ื™ื ืœื”ื™ืฉืืจ ื‘ืžืฆื‘ ืžืฉืชืžืฉ ืชื—ื™ืœื”.

ะฃ lock ืœืชื—ื‘ื™ืจ ื™ืฉ ื”ืคืชืขื•ืช ืžื’ืขื™ืœื•ืช. ืžืžืœื™ืฅ ืœื”ืฉืชืžืฉ Monitor ื™ืฉื™ืจื•ืช [ืจื™ื›ื˜ืจ] [ืืจื™ืง ืœื™ืคืจื˜]. ืื—ื“ ืžื”ื ื”ื•ื ื–ื” lock ืชืžื™ื“ ืžื—ื•ืฅ Monitor, ื’ื ืื ื”ื™ื” ื—ืจื™ื’, ื•ื‘ืžืงืจื” ื–ื” ืฉืจืฉื•ืจ ืื—ืจ ื™ื›ื•ืœ ืœืฉื ื•ืช ืืช ืžืฆื‘ ื”ื–ื™ื›ืจื•ืŸ ื”ืžืฉื•ืชืฃ. ื‘ืžืงืจื™ื ื›ืืœื”, ืœืจื•ื‘ ืขื“ื™ืฃ ืœืœื›ืช ืœืžื‘ื•ื™ ืกืชื•ื ืื• ืœื”ืคืกื™ืง ืื™ื›ืฉื”ื• ืืช ื”ืชื•ื›ื ื™ืช ื‘ื‘ื˜ื—ื”. ื”ืคืชืขื” ื ื•ืกืคืช ื”ื™ื ืฉืžื•ื ื™ื˜ื•ืจ ืžืฉืชืžืฉ ื‘ืœื•ืงื™ ืกื ื›ืจื•ืŸ (SyncBlock), ื”ื ืžืฆืื™ื ื‘ื›ืœ ื”ืื•ื‘ื™ื™ืงื˜ื™ื. ืœื›ืŸ, ืื ื ื‘ื—ืจ ืื•ื‘ื™ื™ืงื˜ ืœื ื”ื•ืœื, ืืชื” ื™ื›ื•ืœ ื‘ืงืœื•ืช ืœืงื‘ืœ ืžื‘ื•ื™ ืกืชื•ื (ืœื“ื•ื’ืžื”, ืื ืืชื” ื ื•ืขืœ ืขืœ ืžื—ืจื•ื–ืช ืคื ื™ืžื™ืช). ืœืฉื ื›ืš ืื ื• ืžืฉืชืžืฉื™ื ื‘ืื•ื‘ื™ื™ืงื˜ ื”ื ืกืชืจ ืชืžื™ื“.

ื“ืคื•ืก ืžืฉืชื ื” ื”ืžืฆื‘ ืžืืคืฉืจ ืœืš ืœื™ื™ืฉื ื‘ืฆื•ืจื” ืชืžืฆื™ืชื™ืช ื™ื•ืชืจ ืืช ื”ืฆื™ืคื™ื™ื” ืœืžืฆื‘ ืžื•ืจื›ื‘ ื›ืœืฉื”ื•. ื‘-.NET, ื–ื” ืœื ืฉืœื, ืœื“ืขืชื™, ื‘ื’ืœืœ ื‘ืชื™ืื•ืจื™ื”, ืฆืจื™ื›ื™ื ืœื”ื™ื•ืช ืžืกืคืจ ืชื•ืจื™ื ื‘ื›ืžื” ืžืฉืชื ื™ื (ื›ืžื• ื‘-Posix Threads), ื•ืœื ื‘ืœื•ืง ืื—ื“. ืื– ืืคืฉืจ ื”ื™ื” ืœื”ื›ื™ืŸ ืื•ืชื ืœื›ืœ ื”ืคื™ืœื•ืกื•ืคื™ื. ืื‘ืœ ื’ื ื‘ืฆื•ืจื” ื–ื•, ื–ื” ืžืืคืฉืจ ืœืš ืœืฆืžืฆื ืืช ื”ืงื•ื“.

ืคื™ืœื•ืกื•ืคื™ื ืจื‘ื™ื ืื• async / await

ืื•ืงื™ื™, ืขื›ืฉื™ื• ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœื—ืกื•ื ืฉืจืฉื•ืจื™ื ื‘ื™ืขื™ืœื•ืช. ืื‘ืœ ืžื” ืื ื™ืฉ ืœื ื• ื”ืจื‘ื” ืคื™ืœื•ืกื•ืคื™ื? 100? 10000? ืœื“ื•ื’ืžื”, ืงื™ื‘ืœื ื• 100000 ื‘ืงืฉื•ืช ืœืฉืจืช ื”ืื™ื ื˜ืจื ื˜. ื–ื” ื™ื”ื™ื” ืชืงื•ืจื” ืœื™ืฆื•ืจ ืฉืจืฉื•ืจ ืขื‘ื•ืจ ื›ืœ ื‘ืงืฉื”, ื›ื™ ื›ืœ ื›ืš ื”ืจื‘ื” ื—ื•ื˜ื™ื ืœื ื™ืคืขืœื• ื‘ืžืงื‘ื™ืœ. ื™ืคืขื™ืœ ืจืง ื›ืžื” ืฉื™ืฉ ืœื™ื‘ื•ืช ืœื•ื’ื™ื•ืช (ื™ืฉ ืœื™ 4). ื•ื›ืœ ื”ืฉืืจ ืคืฉื•ื˜ ื™ื™ืงื—ื• ืžืฉืื‘ื™ื. ืคืชืจื•ืŸ ืื—ื“ ืœื‘ืขื™ื” ื–ื• ื”ื•ื ื“ืคื•ืก ืืกื™ื ื›ืจื•ืŸ / ืžืžืชื™ืŸ. ื”ืจืขื™ื•ืŸ ืฉืœื• ื”ื•ื ืฉื”ืคื•ื ืงืฆื™ื” ืœื ืžื—ื–ื™ืงื” ืืช ื”ืฉืจืฉื•ืจ ืื ื”ื™ื ืฆืจื™ื›ื” ืœื—ื›ื•ืช ืฉืžืฉื”ื• ื™ืžืฉื™ืš. ื•ื›ืืฉืจ ื”ื•ื ืขื•ืฉื” ืžืฉื”ื•, ื”ื•ื ื—ื•ื–ืจ ืœื‘ื™ืฆื•ืข ืฉืœื• (ืื‘ืœ ืœื ื‘ื”ื›ืจื— ื‘ืื•ืชื• ื—ื•ื˜!). ื‘ืžืงืจื” ืฉืœื ื•, ื ื—ื›ื” ืœืžื–ืœื’.

SemaphoreSlim ื™ืฉ ืœื–ื” WaitAsync() ืฉื™ื˜ื”. ื”ื ื” ื™ื™ืฉื•ื ื‘ืืžืฆืขื•ืช ื“ืคื•ืก ื–ื”.

// ะ—ะฐะฟัƒัะบ ั‚ะฐะบะพะน ะถะต, ะบะฐะบ ั€ะฐะฝัŒัˆะต. ะ“ะดะต-ะฝะธะฑัƒะดัŒ ะฒ ะฟั€ะพะณั€ะฐะผะผะต:
Task.Run(() => Run(i, cancelTokenSource.Token));

// ะ—ะฐะฟัƒัะบ ั„ะธะปะพัะพั„ะฐ.
// ะšะปัŽั‡ะตะฒะพะต ัะปะพะฒะพ async -- ะบะพะผะฟะธะปัั‚ะพั€ ั‚ั€ะฐะฝัะปะธั€ัƒะตั‚ ัั‚ะพั‚ ะผะตั‚ะพั‚ ะฒ ะฐัะธะฝั…ั€ะพะฝะฝั‹ะน.
public async Task Run(int i, CancellationToken token)
{
    while (true)
    {
        // await -- ะฑัƒะดะตะผ ะพะถะธะดะฐั‚ัŒ ะบะฐะบะพะณะพ-ั‚ะพ ัะพะฑั‹ั‚ะธั.
        await TakeForks(i);
        // ะŸะพัะปะต await, ะฟั€ะพะดะพะปะถะตะฝะธะต ะฒะพะทะผะพะถะฝะพ ะฒ ะดั€ัƒะณะพะผ ะฟะพั‚ะพะบะต.
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        // ะœะพะถะตั‚ ะฑั‹ั‚ัŒ ะฝะตัะบะพะปัŒะบะพ ัะพะฑั‹ั‚ะธะน ะดะปั ะพะถะธะดะฐะฝะธั.
        await PutForks(i);

        Think(i);

        if (token.IsCancellationRequested) break;
    }
}

async Task TakeForks(int i)
{
    bool hasForks = false;
    while (!hasForks)
    {
        // ะ’ะทะฐะธะผะพะธัะบะปัŽั‡ะฐัŽั‰ะธะน ะดะพัั‚ัƒะฟ ะบ ัั‚ะพะปัƒ:
        await _tableSemaphore.WaitAsync();
        if (forks[Left(i)] == 0 && forks[Right(i)] == 0)
        {
            forks[Left(i)] = i+1;
            forks[Right(i)] = i+1;
            hasForks = true;
        }
        _tableSemaphore.Release();
        // ะ‘ัƒะดะตะผ ะพะถะธะดะฐั‚ัŒ, ั‡ั‚ะพะฑั‹ ัะพัะตะด ะฟะพะปะพะถะธะป ะฒะธะปะบะธ:
        if (!hasForks)
            await _philosopherSemaphores[i].WaitAsync();
    }
}

// ะ–ะดะตะผ ะดะพัั‚ัƒะฟะฐ ะบ ัั‚ะพะปัƒ ะธ ะบะปะฐะดะตะผ ะฒะธะปะบะธ.
async Task PutForks(int i)
{
    await _tableSemaphore.WaitAsync();
    forks[Left(i)] = 0;
    // "ะŸั€ะพะฑัƒะดะธั‚ัŒ" ัะพัะตะดะตะน, ะตัะปะธ ะพะฝะธ "ัะฟะฐะปะธ".
    _philosopherSemaphores[LeftPhilosopher(i)].Release();
    forks[Right(i)] = 0;
    _philosopherSemaphores[RightPhilosopher(i)].Release();
    _tableSemaphore.Release();
}

ืฉื™ื˜ื” ืขื async / await ืžืชื•ืจื’ื ืœืžื›ื•ื ืช ืžืฆื‘ ืžืกื•ื‘ื›ืช ืฉืžื—ื–ื™ืจื” ืžื™ื“ ืืช ื”ืคื ื™ืžื™ ืฉืœื” Task. ื‘ืืžืฆืขื•ืชื• ืชื•ื›ืœื• ืœื”ืžืชื™ืŸ ืœื”ืฉืœืžืช ื”ืฉื™ื˜ื”, ืœื‘ื˜ืœ ืื•ืชื” ื•ื›ืœ ื“ื‘ืจ ืื—ืจ ืฉืชื•ื›ืœื• ืœืขืฉื•ืช ื‘-Task. ื‘ืชื•ืš ื”ืฉื™ื˜ื”, ืžื›ื•ื ืช ื”ืžื“ื™ื ื” ืฉื•ืœื˜ืช ื‘ื‘ื™ืฆื•ืข. ื”ืฉื•ืจื” ื”ืชื—ืชื•ื ื” ื”ื™ื ืฉืื ืื™ืŸ ืขื™ื›ื•ื‘, ืื– ื”ื‘ื™ืฆื•ืข ื”ื•ื ืกื™ื ื›ืจื•ื ื™, ื•ืื ื™ืฉ, ืื– ื”ืฉืจืฉื•ืจ ืžืฉืชื—ืจืจ. ืœื”ื‘ื ื” ื˜ื•ื‘ื” ื™ื•ืชืจ ืฉืœ ื–ื”, ืขื“ื™ืฃ ืœื”ืกืชื›ืœ ืขืœ ืžื›ื•ื ืช ื”ืžื“ื™ื ื” ื”ื–ื•. ืืชื” ื™ื›ื•ืœ ืœื™ืฆื•ืจ ืฉืจืฉืจืื•ืช ืžืืœื” async / await ืฉื™ื˜ื•ืช.

ื‘ื•ืื• ื ื‘ื—ืŸ. ืขื‘ื•ื“ื” ืฉืœ 100 ืคื™ืœื•ืกื•ืคื™ื ืขืœ ืžื›ื•ื ื” ืขื 4 ืœื™ื‘ื•ืช ืœื•ื’ื™ื•ืช, 8 ืฉื ื™ื•ืช. ื”ืคืชืจื•ืŸ ื”ืงื•ื“ื ืขื Monitor ื”ืจื™ืฅ ืจืง ืืช 4 ื”ืฉืจืฉื•ืจื™ื ื”ืจืืฉื•ื ื™ื ื•ื”ืฉืืจ ืœื ืคืขืœ ื‘ื›ืœืœ. ื›ืœ ืื—ื“ ืžืืจื‘ืขืช ื”ื—ื•ื˜ื™ื ื”ืœืœื• ื”ื™ื” ืคืขื™ืœ ื‘ืžืฉืš ื›-4 ืืœืคื™ื•ืช ื”ืฉื ื™ื™ื”. ื•ืคืชืจื•ืŸ ื”-async / await ืจืฅ ืืช ื›ืœ ื”-2, ืขื ื”ืžืชื ื” ืžืžื•ืฆืขืช ืฉืœ 100 ืฉื ื™ื•ืช ื›ืœ ืื—ื“. ื›ืžื•ื‘ืŸ ืฉื‘ืžืขืจื›ื•ืช ืืžื™ืชื™ื•ืช, ืกืจืง ืฉืœ 6.8 ืฉื ื™ื•ืช ืื™ื ื• ืžืงื•ื‘ืœ ื•ืขื“ื™ืฃ ืœื ืœืขื‘ื“ ื›ืœ ื›ืš ื”ืจื‘ื” ื‘ืงืฉื•ืช ื›ืืœื”. ื”ืคืชืจื•ืŸ ืขื Monitor ื”ืชื‘ืจืจ ื›ื‘ืœืชื™ ื ื™ืชืŸ ืœื”ืจื—ื‘ื” ื›ืœืœ.

ืžืกืงื ื”

ื›ืคื™ ืฉื ื™ืชืŸ ืœืจืื•ืช ืžื“ื•ื’ืžืื•ืช ืงื˜ื ื•ืช ืืœื•, .NET ืชื•ืžืš ื‘ืžื‘ื ื™ ืกื ื›ืจื•ืŸ ืจื‘ื™ื. ืขื ื–ืืช, ืœื ืชืžื™ื“ ื‘ืจื•ืจ ื›ื™ืฆื“ ืœื”ืฉืชืžืฉ ื‘ื”ื. ืื ื™ ืžืงื•ื•ื” ืฉืžืืžืจ ื–ื” ื”ื™ื” ืžื•ืขื™ืœ. ืœืขืช ืขืชื” ื–ื” ื”ืกื•ืฃ, ืื‘ืœ ืขื“ื™ื™ืŸ ื ื•ืชืจื• ื”ืจื‘ื” ื“ื‘ืจื™ื ืžืขื ื™ื™ื ื™ื, ืœืžืฉืœ, ืื•ืกืคื™ื ื‘ื˜ื•ื—ื™ื ื‘ืฉืจืฉื•ืจ, TPL Dataflow, ืชื›ื ื•ืช ืจื™ืืงื˜ื™ื‘ื™, ืžื•ื“ืœ ืขืกืงืื•ืช ืชื•ื›ื ื” ื•ื›ื•'.

ืžืงื•ืจื•ืช

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”