ืืึธืืืจ ืืขื ืืื ืงืึทื ืงืขืจืึทื ื ืืื ืคึผืึทืจืึทืืขื ืคึผืจืึธืืจืึทืืืื ื ืึทืจืืขื ืืื .ื ืขื, ื ืืฆื ืื ืคืืืึธืกืึธืคืขืจืก ืืืื ืื ื ืคึผืจืึธืืืขื ืืื ืึท ืืืึทืฉืคึผืื. ืืขืจ ืคึผืืึทื ืืื ืืึธืก, ืคึฟืื ืื ืกืื ืืงืจืึทื ืึทืืืืฉืึทื ืคืื ืคึฟืขืืขื / ืคึผืจืึทืกืขืกืึทื, ืฆื ืืขืจ ืึทืงืืืึธืจ ืืึธืืขื (ืืื ืื ืคืืืืขื ืืข ืคึผืึทืจืฅ). ืืขืจ ืึทืจืืืงื ืงืขื ืืืื ื ืืฆืืง ืคึฟืึทืจ ืืขืจ ืขืจืฉืืขืจ ืืึทืงืึทื ืืขืจ ืึธืืขืจ ืฆื ืืขืจืคืจืืฉื ืืืื ืืืืกื.
ืคืืจืืืืก ืืึธื ืขืก ืืืึท ืึทืืข? ืืจืึทื ืืืกืืขืจื ืืขืจืืจืืืื ืืืืขืจ ืืื ืืืื ืืจืืืก, ืืึธืจ ืก ืืขืืขืฅ ืจืขืกืฅ ืืืืฃ ืื ืืึทืืจืขื ืขืฆืื ื ืคืื ืื ืืืืงืืึทื ืคืื ืืืื ืืื ืืขืจืืืขืจ ืึท ืคืึทืจืืจืขืกืขืจื ืืื ืืืืขืจืงื ืืื ืื ื ืืืขืจ, ืืขืจ ืืจืึทื ืืืกืืขืจื ืงืขื ืขื ืืืื ืืขืืืื. ืืื ืืขืจ ืืขืืืืงืขืจ ืฆืืื, ืื ืกืืืข ืคืื โโืืึทืื ืืื ืืจืึธืืื ื, ืืื ืื ื ืืฆืขืจืก ืืขืจืืืึทืจืื ืึท ืืึทืืืืง ืขื ืืคืขืจ ืคืื ืื ืกืืกืืขืืขื. ืืื ืึทืืึท ืึท ืกืืืืึทืฆืืข, "ื ืึธืจืืึทื" ืคึผืจืึธืืจืึทืืืื ื, ืืืขื ืืืจ ืืึธืื ืืืื ืขืงืกืึทืงืืืืื ื ืคืึธืืขื, ืืื ื ืื ืืขืจ ืขืคืขืงืืืื. ืืืจ ืืึทืจืคึฟื ืฆื ืขืคืขืก ืกืึธืืืืข ืื ืคึผืจืึธืืืขื ืคืื ืกืืืืึทืืืืื ืืึทืก ืึธืืขืจ ืงืึทื ืงืขืจืึทื ื ืืืจืืคืืจืื ื. ืืขืจืฆื, ืืขื ืคึผืจืึธืืืขื ืืืืืกืฅ ืืื ืคืึทืจืฉืืืขื ืข ืืขืืืขืืก: ืืืืฃ ืืขืจ ืืืจืื ืคืื ืคึฟืขืืขื, ืืื ืืขืจ ืืืจืื ืคืื ืคึผืจืึทืกืขืกืึทื, ืืื ืืขืจ ืืืจืื ืคืื ืืืฉืื ืขื ืืื ืื ื ืขืฅ (ืื ืคืื ืื ืืขืจืืขืืืืื ืกืืกืืขืืขื). .ื ืขื ืืื ืืืื-ืงืืืึทืืืืขื, ืฆืืึทื-ืืขืกืืขื ืืขืงื ืึทืืึทืืืฉืื ืคึฟืึทืจ ืืขืฉืืืื ื ืืื ืืคืืฉืึทื ืืื ืกืึทืืืืื ื ืึทืืึท ืคึผืจืึธืืืขืืก.
ืึทืจืืขื
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 ืงืจืืืืฅ ืึธืืขืจ ืจืืืืืื ืคึฟืขืืขื ืืืคึผืขื ืืื ื ืืืืฃ ืื ื ืืืขืจ ืคืื ืื ืืึทืกืงืก. ืืืื ืืขืงื ืคึฟืึทืจ ืึทืืข ืึทืคึผืคึผืืึธืืึทืื ืก. ืืขื ืืขืงื ืืึธื ืืืึทื ืืขื ืืฆื ืึผืืขื ืฉืืขื ืืืง, ืืืืึทื. ื ืื ืืึทืจืคึฟื ืฆื ืึทืจื ืืื ืงืจืืืืืื ื, ืืืกืืขืงื ืคึฟืขืืขื, ืืืืขืจ ืงืืื, ืืื"ื ื. ืขืก ืืื ืืขืืืขื ืึธื ืึท ืืขืงื, ืึธืืขืจ ืืขืืึธืื ืืืจ ืืึธืื ืฆื ื ืืฆื ืขืก ืืืืึทื Thread
, ืืึธืก ืืื ื ืืฆืืง ืคึฟืึทืจ ืงืึทืกืขืก ืืืขื ืืืจ ืืึทืจืคึฟื ืฆื ืืืืฉื ืื ืืืืืขืจืงืืึทื ืคืื ืึท ืคืึธืืขื, ืืืขื ืืืจ ืืึธืื ืึท ืืึทื ื ืึธืคึผืขืจืึทืฆืืข, ืคึฟืึทืจ ืึท ืคืึธืจืืจืึทืื ื ืคืึธืืขื, ืืื"ื ื.
ืืื ืื ืืขืจืข ืืืขืจืืขืจ, System.Threading.Tasks.Task
ืงืืึทืก ืืื ืื ืืขืืืข Thread
, ืึธืืขืจ ืืื ืึทืืข ืกืึธืจืฅ ืคืื ืงืึทื ืืืื ืืึทื ืกืื: ืื ืคืืืืงืืื ืฆื ืืืืคื ืึท ืึทืจืืขื ื ืึธื ืึท ืืืึธืง ืคืื ืื ืืขืจืข ืืึทืกืงืก, ืฆืืจืืงืงืืืขื ืืื ืคืื ืคืึทื ืืงืฉืึทื ื, ืงืึทื ืืืื ืืึทื ืืื ืืืขืจืจืืึทืกื ืืื, ืืื ืืขืจ. ืขืืง ืืื ืืขื ืขื ืืืจืฃ ืฆื ืฉืืืฆื ืึทืกืื ืง / ืืขืจืืืึทืจืื ืงืึทื ืกืืจืึทืงืฉืึทื ื (ืืึทืกืง-ืืืืืจื ืึทืกืื ืืฉืจืึธื ืึธืืก ืืืกืืขืจ, ืกืื ืืึทืงืืืง ืฆืืงืขืจ ืคึฟืึทืจ ืืืืจืื ืคึฟืึทืจ ืืึธ ืึทืคึผืขืจืืืฉืึทื ื). ืืืจ ืืืขืื ืจืขืื ืืืขืื ืืขื ืฉืคึผืขืืขืจ.
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.
ืืื ืื ืคืืืืจ, ืืืึทืงืื ื ืคึฟืขืืขื (ืืึทืืืึทืง). ืืจืื - ืืืจืืคืืจืื ื, ืจืืื - ืกืื ืืงืจืึทื ืึทืืืืฉืึทื, ืืจืื - ืื ืคืึธืืขื ืืื ืกืืืคึผืื ื. ืื ืจืืึธืืืืกืขืก ืึธื ืืืืึทืื ืื ืึธื ืืืื ืฆืืื ืคืื ืืึทืกืงืก.
ืืขืจ ืืื ืืขืจ ืคืื ืื ืคืืืึธืกืึธืคืขื
ืืึธืืฉ ืขืก ืืื ื ืื ื ืืืืืง ืฆื ืืจืึทืืื ืกืคึผืขืฆืืขื ืคืื ืขืกื ืืืึทืจื, ืึธืืขืจ ืืื ืืขืจ ืืืื ืืืขืจ ืขืก ืื ืืขืื ืึทืจืืืฃ ืคืืืึธืกืึธืคืืข. ืืื ืก ืคึผืจืืืืจื ืฆื ืกืืืืืืจื ืื ืกืืืืึทืฆืืข ืคืื โโืืื ืืขืจ ืคืื ืคึฟืขืืขื ืืื ืืื ืืืขืจ ืคึผืจืึธืืืขื. ืืื ืืขืจ ืืื ืืืขื ื ืคืึธืืขื ืืืืคื, ืึธืืขืจ ืึธื ืืึทืืืืืืง ืึทืจืืขื, ืืื ืื ืืขืจืข ืืืขืจืืขืจ, ืืึธืก ืืื ืืขืจ ืืขืืืืงืขืจ ืืขืืืึทืง, ื ืึธืจ ืืืฆื ืื ืคืึธืืขื ืืื ื ืืฉื ืกืืืคึผืื ื, ืึธืืขืจ ืืื ืึทืงืืืืืื ืงืืงื ืคึฟืึทืจ ืขืคึผืขืก ืฆื ืขืกื, ืึธืืขืจ ืขืก ืืื ืงืืื ืขืกื ืืืึทืจื. ืืื ืกืืจ ืฆื ืืืกืืืืื ืึธืคื ืืืึทืงืื ื, ืืืจ ืืืขืื ืฉืืขืื ืื ืืึธืคึผื ืฆืืจืืง ืืืื ืืืจ ืงืขื ื ืืฉื ื ืขืืขื ืื ืื ืืขืจ ืืืื ืขืจ.
// ะขะพ ะถะต ััะพ ะธ ะฒ 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 ืืื ืืืืื ืืงืขืจ ืืื ืฉืืขืื. ืึทืืื ืึท ืงืืืื ืืขืืช ืืื ืื ืงืึธื ืคืืจื ืฆื ืึท ืงืึทืคึผ ืืื ืคืึธืจืฉืืขืืื ื. ืขืก ืืื ืืืื ืืืื ืฆื ืืืืขืจืงื ืืึธ ืึทื ืึท ืืขืืื ืกืืืืึทืฆืืข ืืื ืืขืืืขื ืืืขื ืึทืืข ืคืืืึธืกืึธืคืขืจืก ื ืขืืขื ืื ืืื ืงืก ืืึธืคึผื, ืขืก ืืื ืงืืื ืจืขืื ืืืื ืขืจ, ืืื ืฉืืขืื ืื ืืื ืงืก, ืืืึทืจืื, ื ืขืืขื ืื ืืื ืงืก ืืืืืขืจ, ืืื"ื ื. ืื ืกืืืืึทืฆืืข ืืื ืืืื ืึท ืืื ืืขืจ, ืืขืจ ืืื ืึท ืืขืืืึทืง. ืืื ืืึธื ื ืื ืืขืงืขื ื ืืืืขืจืืืจื. ืื ืืขืจ ืืื ืึท ืืืื ืคึฟืึทืจ ืึท ืกืืืืึทืฆืืข ืืื ืฆืืืื ืฉืืขืื ืคืืืึธืกืึธืคืขืจืก ืืึธืื ืืขื ืืืขื ืืืืืข ืคืึธืจืงืก ืืื ืฆืืืื ืืืืข ืืขื ืขื ืืื ืืขืจืืง.
ืืึธ ืืืจ ืงืขื ืขื ืืขื ืึทื ืื ืคึฟืขืืขื ืืืขืงื ืืื ืืื ืืื ืคึผืจืืืืจื ืฆื ืืึทืงืืืขื ืื ืืืื. ืฆืืืื ืคืื ืื ืคืืจ ืงืึธืจืขืก ืืึธื ืืึธืจื ืืฉื (ืืจืื ืืจืึทืคืืง ืืืืื).
ืืืื ืคืื ืึท ืคืืืึธืกืึธืฃ
ื ื, ื ืื ื ืคืจืืืืขื, ืืืืก ืงืขื ืืืืขืจืืขืจื ื ืืขืจืืืืข ืืื ืขืจ ืคืื ืคืืืืืืคืขื, ืืื ืืืื ืืืื ืขืจ ืคืื ืืื ืฉืืขืจื ืืืืืืื ืืื ืืึธืคื ืืื ืื ืืขื ื (ืืื ืืื ืืืขืื ืืื ืืืื ืืึทืืจืึธืื). ืื ื ืฐืขื ื ื ื ืฉืื ื ื ืืขืืืื ื ื ื ืืืืื . ืืืจ ืงืขื ืขื ืงืืืขื ืึทืจืืืฃ ืืื ืึท ืืืึทืฉืคึผืื ืงืึธื ืคึฟืึทืจ ืืขื ืคืึทื ืืื, ืคึฟืึทืจ ืืืึทืฉืคึผืื, ืขืก ืืื ืืจืื ืืขืืืืจืคื 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
(ืืืึธืก ืืืขืจื ืืึธืจืื ืืขื ืืฆื). ืืืฆื ืฐืฒืก ืขืจ ืฐื ืฆื ืฆืฒืื ืื ืฐืึทืจืืขื ืข, ืืฒ ืึท ืืืกื ืฉืืึธืคึฟื, ืืื ื ืึธื. ืืื' ืืื ืึทืืืขืืืื, ืืื ืึทืืฅ ืืขืืืขื ืฆื ืึทืคึผืืึทืืืื. ืืืขืจ ืืืจ ืืืื ืืขืืขื ืงืขื ืึทื ืืึธืก ืืื ื ืึธื ืืขืจ ืืขืืืืงืขืจ ืึทืงืืืื ืฆืืงื ืืืึธืก ืขืกื ืคึผืจืึทืกืขืกืขืจ ืจืขืกืืจืกื ืืื ืืืื ืื ืืืืคื, ืืืึธืก ืงืขื ืขื ืคืืจื ืฆื ืืื ืืขืจ ืืืื ืืืื ืขืจ ืคืื ืื ืคืืืึธืกืึธืคืขืจืก ืืืขืจื ืืขืจ ืืืืืขืจืงืืึทื ืืื ืื ืืขืจืข, ืึธืืขืจ ืืื ื ืืฉื ืึท ืืึธืืืขื ืืึธืคึผื (ืคึผืจืืึธืจืืื ืื ืืืขืจืืฉืึทื ืคึผืจืึธืืืขื) . ืืขืจืืืขืจ, ืืืจ ื ืืฆื ืขืก ืืืืื ืคึฟืึทืจ ืืืืขืจ ืงืืจืฅ ืขื ืืขืจืื ืืขื ืืื ืฉืขืจื ืืึผืจืื, ืึธื ืงืืื ืืจืื-ืคึผืึทืจืืื ืงืึทืืืก, ื ืขืกืืขื ืืึทืงืก ืืื ืื ืืขืจืข ืกืึทืคึผืจืืืืื.
ืฆืืืืขื ืื ื ืคึฟืึทืจ SpinLock
. ื ื ืฉืืจืื ื ืดืงืืืคื ืด ืฉืืขื ืื ืง ืคื ืจ ืืข ืจ ืืืืืขื ืข ืจ ืืืคื . ืขืก ืืขื ืขื ืคืืืืืขืจื - ืืื ืื ืคืืืืจ, ืื ืืืืกืืขืงืืืื ืืขืื ื. ืื ืงืึธืจืขืก ืืขื ืขื ื ืืฉื ืืึธืจ ืืืืึทืืืืื: ืืืืื ืืืขืื 2/3 ืืืจื ืื ืคืืจ ืคึฟืขืืขื.
ืื ืื ืืขืจ ืืืืืื ื ืืึธ ืืืึธืื ืืืื ืืืืื ืฆื ื ืืฆื Interlocked.CompareExchange
ืืื ืืขืจ ืืขืืืืงืขืจ ืึทืงืืืื ืืืึทืจืื ืืื ืืขืืืืื ืืื ืื ืงืึธื ืืืืื (ืืื ืื ืืื ืืขืจืืง ืคืืืึธืกืึธืคืขืจืก), ืึธืืขืจ ืืึธืก, ืืื ืฉืืื ืืขืืืื, ืงืขื ืืขืึธืจืขืืืฉ ืคืืจื ืฆื ืืืึทืงืื ื.
ืืืืฃ Interlocked
ืขืก ืืึธื ืืืื ืื ืืขืืืืื ืึทื ืขืก ืืื ื ืืฉื ืืืืื CompareExchange
, ืึธืืขืจ ืืืื ืื ืืขืจืข ืืขืืืึธืืก ืคึฟืึทืจ ืึทืืึธืืืฉืข ืืืืขื ืขื ืืื ืฉืจืืึทืื. ืืื ืืืจื ืื ืืืขืจืืึทืืขืจืื ื ืคืื ืื ืขื ืืขืจืื ื, ืืื ืคืึทื ืื ืื ืืขืจ ืคืึธืืขื ืืื ืฆืืื ืฆื ืืึทืื ืื ืขื ืืขืจืื ืืขื (ืืืืขื ืขื 1, ืืืืขื ืขื 2, ืฉืจืืึทืื 2, ืฉืจืืึทืื 1 ืืื ืฉืืขืื), ืขืก ืงืขื ืขื ืืืื ืืขืืืืื ื ืคึฟืึทืจ ืงืึธืืคึผืืขืงืก ืขื ืืขืจืื ืืขื ืฆื ืึท ืืืื ืืืขืจื (Interlocked Anything ืืืกืืขืจ) .
ืงืขืจื ืขื ืืึธืืข ืกืึทืืืฉืึทื ื
ืฆื ืืืกืืืืื ืืืืืกืืื ื ืจืขืกืืจืกื ืืื ืึท ืฉืืืืฃ, ืืึธืืืจ ืืขื ืืื ืืืจ ืงืขื ืขื ืคืึทืจืฉืคึผืึทืจื ืึท ืคืึธืืขื. ืืึธืก ืืฒืกื, ืฐืฒึทืืขืจ ืืื ืืืขืจ ืืฒึทืฉืคึผืื, ืืึธืืืจ ืืขื, ืฐื ืืขืจ ืงืขืื ืขืจ ืฉืืึธืคึฟื ืืขื ืคึฟืืืึธืกืึธืฃ ืืื ืฐืขืงื ืืื ื ืึธืจ ืฐืขื ืขืก ืืื ื ืืืืืง. ืขืจืฉืืขืจ, ืืึธืืืจ ืืขื ืืื ืฆื ืืึธื ืืึธืก ืืืจื ืื ืงืขืจื ืืึธืืข ืคืื โโโโืื ืึธืคึผืขืจืืืืื ื ืกืืกืืขื. ืึทืืข ืกืืจืึทืงืืฉืขืจื ืืึธืจื ืืขื ืขื ืึธืคื ืกืืึธืืขืจ ืืื ืืขื ืข ืืื ืืึทื ืืฆืขืจ ืคึผืืึทืฅ. ืขืืืขืืข ืืึธื ืกืืึธืืขืจ, ืืืฉื AutoResetEvent
ืืคึฟืฉืจ 53 ืืื ืกืืึธืืขืจ SpinLock
[ืจืืืืขืจ]. ืึธืืขืจ ืืื ืืืืขืจ ืืืืฃ, ืืืจ ืงืขื ืขื ืกืื ืืงืจืึทื ืืื ืคึผืจืึทืกืขืกืึทื ืืืืขืจ ืื ืกืืกืืขื, ืืขืจืืื ืึธืืขืจ ื ืืฉื.
ืื ืืจืื ื ืงืึทื ืกืืจืึทืงื ืืึธ ืืื ืื ืกืขืืึทืคืึธืจืข ืคืืจืืขืืืืื ืืืจื Dijkstra ืืื ืึท ืืึทืื ืืึธืจืืื ืืขืจื ืฆืืจืืง. ื ืกืขืืึทืคืึธืจ ืืื, ืคืฉืื ืฉืืขืื, ืึท positive ืื ืืึทืืืฉืขืจ ืืขืจืืื ืืืจื ืื ืกืืกืืขื, ืืื ืฆืืืื ืึทืคึผืขืจืืืฉืึทื ื ืืืืฃ ืขืก, ืื ืงืจืึทืืึทื ื ืืื ืืืงืจืึทืืึทื ื. ืืืื ืขืก ืคืืืื ืฆื ืคืึทืจืืื ืขืจื, ื ืื, ืื ืคืึทื ืคืึธืืขื ืืื ืืคืืขืฉืืขืื. ืืืขื ืื ื ืืืขืจ ืืื ืื ืงืจืึทืืึทื ืืื ืืืจื ืขืืืขืืข ืื ืืขืจืข ืึทืงืืืื ืคืึธืืขื / ืคึผืจืึธืฆืขืก, ืื ืคึฟืขืืขื ืืขื ืขื ืกืงืืคึผื ืืื ืื ืกืขืืึทืคืึธืจืข ืืื ืืืืืขืจ ืืืงืจืืกื ืืืจื ืื ืืืจืืืขืืื ืืขื ื ืืืขืจ. ืืขื ืงืขื ืืื ืคืืจืฉืืขืื ืืื ืขื ืืื ื ืืืืื ืขืง ืืื ื ืกืขืืืคืืจ. .ื ืขื ืึธืคืคืขืจืก ืขืืืขืืข ืงืึทื ืกืืจืึทืงืฉืึทื ื ืืื ืขื ืืขื ืคืึทื ืืงืฉืึทื ืึทืืืื: 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 (ืืืืขืงืก), ืึธืืขืจ ืืื ืฉืืืฆื ืคึฟืึทืจ ืืืืจืื ืืื ืึท ืฉืืืืฃ, ืจืขืงืืจืกืืึธื, ืื ืงืึธื ืืืืืึธื ืืืึทืจืืึทืืืข ืืืกืืขืจ (ืืขืจ ืืืืฃ ืึทื ืืื ืื), ืืื"ื ื. ืืึธืืืจ ืงืืงื ืืื ืึท ืืืืืื ื ืืื ืืื.
// ะกะฟัััะตะผ ะพะฑัะตะบั ะดะปั ะะพะฝะธัะพัะฐ ะพั ะฒัะตั
, ััะพะฑั ะฑะตะท ะดะตะดะปะพะบะพะฒ.
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
), ืืืึธืก ืืขื ืขื ืคืึธืจืฉืืขืื ืืื ืึทืืข ืึทืืืืฉืขืงืฅ. ืืขืจืืืขืจ, ืืืื ืึท ืื ืึทืคึผืจืึธืืคึผืจืืื ืืืืคืขืฅ ืืื ืืืืกืืขืงืืืื, ืืืจ ืงืขื ืขื ืืืืื ืืึทืงืืืขื ืึท ืืขืืืึทืง (ืืืฉื, ืืืื ืืืจ ืฉืืึธืก ืืืืฃ ืึท ืื ืืขืจื ืขื ืฉืืจืืงื). ืืืจ ื ืืฆื ืื ืฉืืขื ืืืง ืคืึทืจืืึธืจืื ืืืืคืขืฅ ืคึฟืึทืจ ืืขื.
ืื ืงืึธื ืืืืืึธื ืืืึทืจืืึทืืืข ืืืกืืขืจ ืึทืืึทืื ืืืจ ืฆื ืืขืจ ืงืึทื ืกืืืกืื ืื ืกืืจืืืขื ื ืื ืืขืจืืืึทืจืืื ื ืคืื ืขืืืขืืข ืงืึธืืคึผืืขืงืก ืฆืืฉืืึทื ื. ืืื .ื ืขื, ืขืก ืืื ืืขืจืขื ืืืงื, ืืื ืืืื ืืืื ืื ื, ืืืืึทื ืืื ืืขืึธืจืืข, ืขืก ืืึธื ืืืื ืขืืืขืืข ืงืืื ืืืืฃ ืขืืืขืืข ืืืขืจืืึทืืึทืื (ืืื ืืื Posix ืคึฟืขืืขื), ืืื ื ืืฉื ืืืืฃ ืืืื ืืึธืืง. ืืขืืื ื ืื ื ืืข ื ื ืฒ ืืขืงืขื ื ืืื ื ืคื ืจ ืื ืข ืคืืืืกืืคื . ืึธืืขืจ ืืคืืื ืืื ืืขื ืคืึธืจืขื, ืขืก ืึทืืึทืื ืืืจ ืฆื ืจืขืืืฆืืจื ืื ืงืึธื.
ืคืืืข ืคืืืึธืกืึธืคืขืจืก ืึธืืขืจ 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
. ืืืจื ืขืก, ืืืจ ืงืขื ืขื ืืืึทืจืื ืคึฟืึทืจ ืื ืงืึทืืคึผืืืฉืึทื ืคืื ืืขื ืืืคึฟื, ืืึธืื ืืึทืื ืขืก ืืื ืึทืืฅ ืึทื ืืขืจืฉ ืืืจ ืงืขื ืขื ืืึธื ืืื ืืึทืกืง. ืืื ืืขื ืืืคึฟื, ืื ืฉืืึทื ืืึทืฉืื ืงืึธื ืืจืึธืืก ืื ืืืจืืคืืจืื ื. ืื ืื ืึธ ืฉืืจื ืืื ืึทื ืืืื ืขืก ืืื ืงืืื ืคืึทืจืืึทืืื, ืื ืืืจืืคืืจืื ื ืืื ืกืื ืืฉืจืึธื ืึธืืก, ืืื ืืืื ืขืก ืืื, ืืขืจ ืคืึธืืขื ืืื ืคืจืื. ืคึฟืึทืจ ืึท ืืขืกืขืจ ืคืืจืฉืืื ื ืคืื ืืขื, ืขืก ืืื ืืขืกืขืจ ืฆื ืงืืงื ืืื ืืขื ืฉืืึทื ืืึทืฉืื. ืืืจ ืงืขื ืขื ืืึทืื ืงืืืื ืคืื ืื async
/ await
ืืขืืืึธืืก.
ืืื ืก ืคึผืจืืืืจื. ืึทืจืืขื ืคืื 100 ืคืืืึธืกืึธืคืขืจืก ืืืืฃ ืึท ืืึทืฉืื ืืื 4 ืืึทืืืฉืืงืึทื ืงืึธืจืขืก, 8 ืกืขืงืื ืืขืก. ืื ืคืจืืขืจืืืงืข ืืืืืื ื ืืื ืืึธื ืืืึธืจ ืืืืื ืืขืืืคื ืื ืขืจืฉืืขืจ 4 ืคึฟืขืืขื ืืื ืื ืื ืืื ืืื ื ืืฉื ืืืืคื ืืื ืึทืืข. ืืขืืขืจ ืคืื ืื 4 ืคึฟืขืืขื ืืื ืืืืืืง ืคึฟืึทืจ ืืืขืื 2ms. ืืื ืื ืึทืกืื ืง / ืืขืจืืืึทืจืื ืืืืืื ื ืืื ืืขืืืขื ืึทืืข 100, ืืื ืึท ืืืจืืฉื ืืืืขื ืืืึทืจืื ืคืื 6.8 ืกืขืงืื ืืขืก ืืขืืขืจ. ืคืื ืงืืจืก, ืืื ืคืึทืงืืืฉ ืกืืกืืขืืขื ืืืืืืง ืคึฟืึทืจ 6 ืกืขืงืื ืืขืก ืืื ืึทื ืึทืงืกืขืคึผืืึทืืึทื ืืื ืขืก ืืื ืืขืกืขืจ ื ืืฉื ืฆื ืคึผืจืึธืฆืขืก ืึทืืื ืคืืืข ืจืืงืืืขืก ืืื ืืึธืก. ืื ืืืืืื ื ืืื ืืึธื ืืืึธืจ ืืื ืืขืืืขื ื ืื ืกืงืึทืืึทืืืข ืืืึท ืึทืืข.
ืกืึธืฃ
ืืื ืืืจ ืงืขื ืขื ืืขื ืคืื ืื ืงืืืื ืืืืฉืคืืื,. ื ืขืฅ ืฉืืืฆื ืคืืืข ืกืื ืืงืจืึทื ืึทืืืืฉืึทื ืงืึทื ืกืืจืึทืงืฉืึทื ื. ืึธืืขืจ, ืขืก ืืื ื ืื ืฉืืขื ืืืง ืงืืึธืจ ืืื ืืขืจ ืืึธื ืืื ืฆื ื ืืฆื ืืื. ืืื ืืึธืคึฟื ืืขื ืึทืจืืืงื ืืื ืืขืืืขื ื ืืฆืืง. ืคึฟืึทืจ ืืืฆื, ืืึธืก ืืื ืืขืจ ืกืืฃ, ืึธืืขืจ ืขืก ืืขื ืขื ื ืึธื ืึท ืคึผืืึทืฅ ืคืื ืืฉืืงืึทืืืข ืืืื ืืื ืงืก, ืืืฉื, ืคืึธืืขื-ืืืืขืจ ืืึทืืืื ืืขื, TPL Dataflow, ืจืืึทืงืืืื ืคึผืจืึธืืจืึทืืืื ื, ืืืืืืืืืจื ืืจืึทื ืกืึทืงืืืึธื ืืึธืืขื, ืขืืง.
ืงืืืืื
- ืืืืคื ืืืืืฉืืืึทืืึทืืืืฉืึทื:
ืงืึธื ืงืืจืจืขื ืกื ืืืืกืืึทืืืืขืจ - MSDN:
ืืจืขืืื ื ,ืึทืกืื ืืฉืจืึธื ืึธืืก ืคึผืจืึธืืจืึทืืืื ื ืคึผืึทืืขืจื ื ืืื ืคืืืข ืื ืืขืจืข ืื ืืขืจืข - [Richter] - CLR ืืืจื C #, Jeffrey Richter
- [ืขืจืืง ืืืคึผืขืจื] -
ืืืขืื ืฉืืึธืก ืืงืืจ ืงืึธื - ืืืื - "ืืึทื ืฅ ืฆืืืืฉื ืฉืืืขืจืื", ื. ืกืขืืืจืึทืืกืงื
ืืงืืจ: www.habr.com