Philosophers Dining Problem ááᯠááá°áá¬á¡ááŒá Ạá¡áá¯á¶ážááŒá¯á .Net ááœáẠáá áºááŒáá¯ááºáááºáž ááŸáá·áº á¡ááŒáá¯áẠáááá¯ááááºážáááºáž áááºááá¯á· á¡áá¯ááºáá¯ááºáááºááᯠááŒáá·áºááŒáá«á áá¯á·á á¡á á®á¡á á¥áºááẠááœá²áá»á¬áž/áá¯ááºáááºážá ááºáá»á¬ážááᯠáááºáá°ááŒá¯ááŒááºážá០ááá¯ááºáá±á¬ááºáá±á¬áºáááºá¡áá (á¡á±á¬ááºáá«á¡ááá¯ááºážáá»á¬ážááœááº) ááŒá áºáááºá áá±á¬ááºážáá«ážááẠááááá¯á¶ážá¡ááááááºááœá±á¡ááœáẠááá¯á·ááá¯áẠááá·áºá¡ááááá¬ááᯠááŒááºáááºáááºážáá áºáááºá¡ááœáẠá¡áá¯á¶ážáááºáá±áááºá
áá¬ááŒá±á¬áá·áº á¡áá¯ááºáá¯ááºáá¬áá²á ááááºá á á¹á áá¬áá»á¬ážááẠáááºážááá¯á·á á¡áááá·áºáá¯á¶ážá¡ááœááºá¡á á¬ážááá¯á· áá±á¬ááºááŸáááŒá®ážá Moore á á¥ááá±ááẠá¡áááºážá á¡ááŒááºááŸá¯ááºáž ááá·áºáááºáá»ááºáá±á«áºááœáẠáááºááŸááá±ááŒá®áž ááá¯á·ááŒá±á¬áá·áº á¡áá±á¡ááœáẠááá¯ážáá¬áááºááᯠááœá±á·ááŸáááááŒáá·áº ááááºá á á¹á áá¬áá»á¬ážááᯠááá¯ááá¯áá¯ááºáá±á¬ááºááá¯ááºáááºá áá áºáá»áááºáááºážááŸá¬áááºá áá±áá¬ááá¬áááá¯ážááœá¬ážáá¬áᬠáá¯á¶ážá áœá²áá°áá»á¬ážááẠá áá áºáá»á¬ážá០áá»ááºáá»ááºážáá¯á¶á·ááŒááºááŸá¯ááᯠáá»áŸá±á¬áºááá·áºááŒáááºá ááá¯ááá¯á·áá±á¬á¡ááŒá±á¡áá±áá»áá¯ážááœááºá áá»áœááºá¯ááºááá¯á·ááœáẠáá¯ááºáá±á¬ááºáá±áá±á¬ thread áá áºáá¯ááŸááá±á¬á¡áá« "áá¬áááº" áááá¯ááááºááẠáááá±á¬ááºááŸá¯áááŸááá±á¬á·áá«á áá áºááŒáá¯ááºáááºáááºáž ááá¯á·ááá¯áẠáá áºááŒáá¯ááºáááºáááºáž áá¯ááºáá±á¬ááºááŒááºážá ááŒá¿áá¬ááᯠááẠáá áºáááºážáááºážááŒáá·áº ááŒá±ááŸááºážááẠááá¯á¡ááºáááºá ááá¯á·á¡ááŒááºá á€ááŒá¿áá¬ááẠááá°áá®áá±á¬á¡ááá·áºáá»á¬ážááœáẠááŸááá±áááº- thread á¡ááá·áºá áá¯ááºáááºážá ááºá¡ááá·áºááœááºá ááœááºáááºá¡ááœááºážááŸá á ááºáá»á¬ážá¡ááá·áº (ááŒáá·áºáá±áá¬ážáá±á¬á áá áºáá»á¬áž)á .NET ááœáẠááá¯ááá¯á·áá±á¬ááŒá¿áá¬áá»á¬ážááᯠáá»ááºááŒááºáááá±á¬ááºá áœá¬ááŒá±ááŸááºážáááºá¡ááœáẠá¡áááºá¡ááœá±ážááŒáá·áºááŒá®áž á¡áá»áááºááŸáá·áºáááŒá±ážáá®á ááºážáááºáá¬ážáá±á¬áááºážááá¬áá»á¬ážááŸááááºá
áá¯ááºáááºáž
Edsger Dijkstra ááẠá€ááŒá¿áá¬ááᯠ1965 áá¯ááŸá áºá¡á á±á¬ááá¯ááºážááœáẠáá°ááá»á±á¬ááºážáá¬ážáá»á¬ážáᶠáááºááŒáá²á·áááºá ááœá²á·á ááºážááŸá¯áá¯á¶á á¶ááŸá¬ á¡á±á¬ááºáá«á¡ááá¯ááºážááŒá áºáááºá áá¿áááá¬ááŸááºá¡áá»áá¯á· (áá»á¬ážáá±á¬á¡á¬ážááŒáá·áº áá«ážáá±á¬ááº) ááŸáá·áº áá°áá®áá±á¬ áááºáááºážááœá²á¡áá±á¡ááœáẠááŸááááºá á á¬ážááœá²ááá¯ááºážááŸá¬ ááá¯ááºááŒááŒá®áž áá°ááá¯á·ááŒá¬ážá áááºáááºážááœááœá±á áá¿áááá¬ááŸááºáá»á¬ážááẠáááºážááá¯á·á á¡áá¯á¶ážáááŸááá±á¬ áááºážáááºááŒá¬ážáá»á¬ážá០á á¬ážááá¯ááºáááºá ááœá±ážáá±á¬ááá¯ááºááẠááá¯á·ááá¯áẠá á±á¬áá·áºááá¯ááºážááá¯ááºáááºá áá¿áááá¬ááŸááºáá áºáŠážááá¯á á¬ážááẠáááºááẠáááºáááºážááŸá áºáá»á±á¬ááºážáá°ááẠááá¯á¡ááºááẠ(áá±á¬ááºáá¯á¶ážáá áºáá¯ááẠááááá áºáá¯ááŸáá·áº áááºáááºážááá¯áá»áŸáá±áááº)á áááºážáá¯á¶áááºážááœááᯠáá±á¬ááºááŒááºážááŸáá·áº áá»ááŒááºážááẠáá®ážááŒá¬ážáá¯ááºáá±á¬ááºááŸá¯ ááŸá áºáá¯ááŒá áºáááºá áá¿áááá¬ááŸááºá¡á¬ážáá¯á¶áž ááááºááááºáá±ááŒáááºá áá¬áááºááŸá¬ á á ááŸá áºááŒá¬ááŒá®ážáá±á¬ááºááœááºááẠáááºážááá¯á·á¡á¬ážáá¯á¶áž ááœá±ážáááºáᬠááŒáá·áºáá±ááá·áº á¡ááºáááá¯áá®áááºáá áºáá¯ááᯠááŸá¬ááœá±áááºááŒá áºáááºá
áŠážá áœá¬á áá»áŸáá±áá¬ážáá±á¬áá±áá¬ááᯠá¡áá¯á¶ážááŒá¯ááŒááºážááŒáá·áº á€ááŒá¿áá¬ááᯠááŒá±ááŸááºážááŒáá«á áá¯á·á áááºáááºážááœáá»á¬ážááẠá¡áá»á¬ážáá°ááŸá¬ á á¬ážááœá²áá±á«áºááœáẠááŸá²áá±ááŒá®áž áá¿áááá¬ááŸááºáá»á¬ážááẠáááºážááá¯á·ááŸáááá·áºá¡áá«ááœáẠáááºážááá¯á·ááᯠááá¯ážááá¯ážááŸááºážááŸááºážáá°á ááŒááºáá¬ážááŒáááºá á€áá±áá¬ááœáẠsurebets ááᯠá¡ááá¡áá»áá°ááẠáááºááá·áºá¡áá»áááºááœáẠáááºáá°ááŒá¯ááŒááºážááœáẠááŒá¿áá¬áá»á¬ážááŸááá«áááºá áááºážáá¯á¶áááºážááœáááŸáááẠáááºááá¯áá¯ááºááá²á á áááºááá¯á·ááᯠáŠážá áœá¬áááá áá¿áááá¬ááŸááºáá»á¬ážááᯠá áááºááŒáá«á áá¯á·á
á
á¬ááœá²áá»á¬ážá
áááºááẠáá»áœááºá¯ááºááá¯á·ááẠthread pool ááá¯á¡áá¯á¶ážááŒá¯áááºá 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);
}
thread pool ááẠthread áááºáá®ážááŒááºážááŸáá·áº áá»ááºááŒááºážááá¯á·ááᯠá¡áá±á¬ááºážáá¯á¶ážááŒá
áºá¡á±á¬áẠáá®ááá¯ááºážáá¯ááºáá¬ážáááºá á€á¡á
á¯á¡áá±ážááœáẠáá¯ááºáá±á¬ááºá
áá¬áá»á¬ážáá«ááá·áº áááºážá
á®áá
áºáá¯ááŸáááŒá®áž CLR ááẠá¡ááá¯áá«áá¯ááºáá±á¬ááºá
áá¬á¡áá±á¡ááœááºáá±á«áºáá°áááºá á
á¬ááœá²áá»á¬ážááᯠáááºáá®áž ááá¯á·ááá¯áẠáááºááŸá¬ážáááºá AppDomains á¡á¬ážáá¯á¶ážá¡ááœáẠáá±áá°ážáááºáá
áºáá¯á áá¬ááŒá±á¬áá·áºáá²ááá¯áá±á¬á· áá®áá±áááºááᯠá¡ááŒá²áááºážááá¯ááᯠáá¯á¶ážááá·áºáá«áááºá á
á¬ááœá²áá»á¬áž áááºáá®ážááŒááºážá áá»ááºááŒááºážá áááºážááá¯á·á áááºážá
á®ááŒááºáž á
áááºááá¯á·ááᯠááŸá±á¬ááºááŸááºááẠáááá¯á¡ááºáá«á áá±áá°ážáááºááá«áá² ááŒá
áºááá¯ááºáá±á¬áºáááºáž áááºážááᯠááá¯ááºááá¯ááºá¡áá¯á¶ážááŒá¯ááẠááá¯á¡ááºáá«áááºá Thread
á áá»áœááºá¯ááºááá¯á·ááœáẠááŒá¬ááŸááºá
áœá¬áá¯ááºáá±á¬ááºááŸá¯áá
áºáá¯á Foreground thread á
áááºááá¯á·á¡ááœáẠáááºá thread áá
áºáá¯á áŠážá
á¬ážáá±ážááᯠááŒá±á¬ááºážáá²ááẠááá¯á¡ááºáá±á¬á¡áá«ááœáẠáááºážááẠá¡áá¯á¶ážáááºáááºá
áá
áºáááºážááŒá±á¬ááááºáá±á¬á·, System.Threading.Tasks.Task
á¡áááºážááá±á¬á· á¡áá°áá°áá«áá²á Thread
á¡áááºááŒá±ááŸá¯á¡áá»áá¯ážáá»áá¯ážááŒáá·áº- á¡ááŒá¬ážáá¯ááºáá±á¬ááºá
áá¬áá»á¬ážááᯠááááºááá¯á·ááŒá®ážáá±á¬áẠáá¯ááºáá±á¬ááºááá¯ááºááŸá¯á áá¯ááºáá±á¬ááºáá»ááºáá»á¬ážá០áááºážááá¯á·ááᯠááŒááºáá±ážááŒááºážá áááºážááá¯á·ááᯠá¡áááºááŒá±á
áœá¬ ááŸá±á¬áá·áºááŸááºááŒááºážááŸáá·áº á¡ááŒá¬ážá¡áá¬áá»á¬áž áá¯ááºáá±á¬ááºááá¯ááºááŒááºážá á
áááºááá¯á·ááᯠasync/ait builds áá»á¬ážááᯠáá¶á·ááá¯ážááẠáááºážááá¯á·ááẠááá¯á¡ááºááẠ(Task-based Asynchronous Patterná IO áá¯ááºáá±á¬ááºááŸá¯áá»á¬ážááᯠá
á±á¬áá·áºááá¯ááºážáááºá¡ááœáẠsyntactic áááŒá¬áž)á áá®á¡ááŒá±á¬ááºážááᯠáá±á¬ááºááŸááŒá±á¬áá«áááºá
CancelationTokenSource
calling thread á signal ááœáẠthread ááẠáá°á·áá¬áá¬áá° á¡áá¯á¶ážáááºááá¯ááºá
á±ááẠá€áá±áá¬ááœáẠááá¯á¡ááºáá«áááºá
áááºáá°áá»áá±á¬ ááŒá¿áá¬áá»á¬áž
ááááºááá¯á·áá¶áá¬ážááá±á¬ áá¿áááááá¬ááŸááº
áá±á¬ááºážááŒá®á á á¬ááŒá±á¬ááºážáá»á¬ážáááºáá®ážáááºážááᯠáá»áœááºá¯ááºááá¯á·áááááºá áá±á·áááºá á¬á á¬ážááŒáá«á áá¯á·á
// ÐÑП какОе вОлкО взÑл. РпÑОЌеÑÑ: 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 ááẠprocessor ááá¯áá°ááẠ(Thread.SpinWait
) ááá¯á·áá±á¬áº áá
áºáá«áá
áºáá¶ááœáẠááááºážáá»á¯ááºááŸá¯ááᯠá¡ááŒá¬ážá¡ááŒá±á¬ááºážá¡áá¬ááá¯á· ááœáŸá²ááŒá±á¬ááºážáá±ážááẠ(Thread.Yeild
) ááá¯á·ááá¯áẠá¡áááºáá»á±á¬áºááœá¬ážááẠ(Thread.Sleep
).
áá«áá±ááá·áº áá®ááŒá±ááŸááºážáá»ááºá á¡áá¯ááºáááŒá áºáá¬ááŒá±á¬áá·áºáá«á áááŒá¬áá® (áá«á·á¡ááœáẠáá áºá áá¹ááá·áºá¡ááœááºáž) á á®ážáááºážááŸá¯ááᯠááááºááá¯á·ááœá¬ážáááº- áá¿áááá¬ááŸááºá¡á¬ážáá¯á¶ážááẠáááºážááá¯á·á áááºáááºááœáá¯á¶ááᯠáá°áá±á¬áºáááºáž áá¬áááºááᯠááá°áá«á ááá¯á·áá±á¬áẠforks array ááœáẠáááºááá¯ážáá»á¬áž ááŸááááº- 1 2 3 4 5 á
áá¯á¶ááœááºá thread áá»á¬ážááá¯ááááºááá¯á·ááŒááºáž (deadlock)á á¡á áááºážáá±á¬áẠ- ááœááºáá»ááºááŒááºážá á¡áá®áá±á¬áẠ- áááºáá°ááŒá¯ááŒááºážá áá®ážááá¯ážáá±á¬áẠ- áá»ááºáá»áŸááºáááºá¡áááºáá»á±á¬áºáá±áááºá á¡áá¯ááºáá»á¬ážááẠTasks áá áááºáá»áááºááá¯ááœáŸááºááŒáááºá
The Hunger of the Philosophers
á¡áá°ážáááŒáá·áº á¡á á¬ážá¡áá±á¬áẠá¡áá»á¬ážááŒá®áž ááœá±ážááá¯á· áááá¯á¡ááºáá±ááá·áº áááºááœááºááŸá¯á áááºáá°áááᯠá¡ááœá±ážá¡áá±á«áºááᯠá¡ááŸá¯á¶ážáá±ážá á±áááºá áá»áœááºá¯ááºááá¯á·áááŒá¿áá¬ááŸá áá»ááºáá»áŸááºáá»á¬ážá áááºááœááºáá±á«ááºážáá«ážááŸá¯á¡ááŒá±á¡áá±ááᯠáá¯á¶áá±á¬áºááŒáá·áºáá¡á±á¬ááºá áááºááœááºááŒááºážááẠáá»ááºáá»áŸááºáá áºáá¯áááºáááºáá±áá±á¬áºáááºáž áááá¬áááºááŸá¬ážáá±á¬á¡áá¯ááºáááŸááá²á áá áºáááºážá¡á¬ážááŒáá·áºááŒá±á¬ááá»áŸáẠá€á¡áá¬ááẠáá°áá®áá±á¬ááá±áá¹áá¬ááŒá áºáááºá ááá¯áá¬áá»ááºáá»áŸááºááẠá¡áááºááá»á±á¬áºáá±á¬áºáááºáž á á¬ážá áá¬áá áºáá¯áá¯ááᯠáááºááŒáœá áœá¬ááŸá¬ááœá±áá±áá±á¬áºáááºáž á¡á á¬áááŸááá±á áááŒá¬áá ááááºááá¯á·ááŒááºážááᯠááŸá±á¬ááºááŸá¬ážááẠá¡ááŒá¬ážáá áºáá¯ááᯠááá°ááá¯ááºáá²á·áá«á áááºáááºážááᯠááŒááºáá¬ážáá«áááºá
// ТП же ÑÑП О в 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)
);
}
á€áá¯ááºá á¡áá±ážááŒá®ážáá±á¬á¡áá»ááºááŸá¬ áá¿áááá¬ááŸáẠáá±ážáŠážááœáẠááŸá áºáŠážááẠáááºážááá¯á·á áááºáááºááœáá¯á¶ááᯠáá»ááẠáá±á·áá»á±á¬á·áá±ááŒááºážááŒá áºáááºá á¡áá»áŸááºáá»á¬ážááẠáá°áá®áá±á¬áŠážá á¬ážáá±ážááŒá áºáá±á¬áºáááºáž á¡ááŒá¬ážáá°áá»á¬áž á¡á á¬áááºáá¬áá»áááºááœáẠáááºážááá¯á·ááẠá¡á á¬ááá¯á á¬ážááŒáááºááᯠááœá±á·ááŸáááááºá áá®ááŸá¬ áá°ááá¯á· áá¯á¶ážá áááºáá±áᬠááá¯ááºáá°ážá ááá±á¬ááºážáá²á· áá¿áááá¬ááŸááºááœá±áᬠáá áºáá«áá áºáá¶ááŸá¬ áá°ááá¯á·áá²á· ááœáá¯á¶ááœá±ááᯠáá»á±á¬ááá¯ááºážáá¬ážááŒáá«áááºá áá°áá±á¬ááºážááœá± á á¬ážáᬠááá±á¬ááºážáá¬ááẠá ááá±á¬áẠááá¯áááºážáááºá ááá¯á·ááŒá±á¬áá·áº áá¯ááºááœáẠáá±ážáááºáá±á¬ á¡ááŸá¬ážááẠá áœááºážáá±á¬ááºááẠáá»áááºážááœá¬ážá á±áááºá áá¿áááá¬ááŸááºá¡á¬ážáá¯á¶áž áááºáááºáááºážáá¯á¶ááᯠááá¯ááºááá¯ááºá áá¬áááºáááŸáá áááºáááºáá¬ážá á á±á¬áá·áºá áááºáááºááŒááºáá°á á áááºááŒáá·áº ááŒá¯á¶áá±á¬áá·áºááŒá¯á¶áá² á¡ááŒá±á¡áá±áá áºáᯠááŒá áºááá¯ááºáááºááá¯áááºáž á€áá±áá¬ááœáẠáááááŒá¯ááá·áºáááºá á€á¡ááŒá±á¡áá±ááẠáááºááœááºáá±á«ááºážáá«ážááŸá¯áá áºáá¯ááŒá áºááŒá®áž ááá±ááá»á¬ááŒá áºáá±ááá·áº á¡ááŒá±á¡áá±áá áºáá¯áááºážááŒá áºáááºá áááºááŒá±á¬ááá¯á· áá»ááºááœááºáá²á·áááºá á¡á±á¬ááºáá±á¬áºááŒáá«áá¯á¶ááẠááá±á¬ááºážáá²á·áá¿áááá¬ááŸááºááŸá áºáá±á¬áẠáááºážááœá²ááá¯ááºááŒááŒá®áž áá±á¬ááºážáá°ááŸá áºáá±á¬áẠáááºáá±áá²á· á¡ááŒá±á¡áá±á¡ááœáẠáá¯á¶ááŒá áºáá«áááºá
á€áá±áá¬ááœáẠá á¬ááœá²áá»á¬ážááẠáá áºáá«áá áºáᶠááá¯ážááá¬ááŒá®áž á¡áááºážá¡ááŒá áºááᯠááá°ááẠááŒáá¯ážá á¬ážáááºááᯠá€áá±áá¬ááœáẠáááºááœá±á·ááŒááºááá¯ááºáá«áááºá core áá±ážáá¯áá²á ááŸá áºáá¯á áá¬ááŸááá¯ááºáá«áá°áž (á¡áááºá ááááºá¡á áááºáž)á
áá¿áááááá¬ááŸááºáá áºáŠážáá±áá¯á¶áž
áá±á¬ááºážááŒá®á áá¿áááá¬ááŸááºááá¯á·á áá»ááºááá±ááŸááá±á¬ áá
á¬á
á¬ážááœá²ááᯠááŸá±á¬ááºááŸááºááá¯ááºááá·áº áá±á¬ááºááŒá¿áá¬áá
áºáá¯ááŸá¬ áááºážááá¯á·á¡áááºá០áá
áºáŠážááẠáá¯ááºáááẠáááºáááºážááœááŒáá·áº áá±áá¯á¶ážááœá¬ážáá«á (ááá¯áá²á·ááá¯á· ááŒáŸá¯ááºááŸá¶áááº)á ááá¯á·áá±á¬áẠá¡áááºáá®ážáá¬ážáá»ááºážáá»á¬ážááᯠáá±á·áááºá
ᬠáá
á¬ážáá² áá¬ážáá²á·áááºá á€ááá
á¹á
á¡ááœáẠáááºááá¯ááºááá¯áẠá¥ááá¬áá¯ááºáá
áºáᯠáááºáá¬ááá¯ááºáááºá á¥ááá¬á áááºážááᯠáá¯ááºáá
áºááá¯ááºáá«á NullReferenceException
áá¿áááá¬ááŸááºááẠáááºáááºážáá»á¬ážááᯠáá°ááŒá®ážáá±á¬ááºá ááŒá®ážáá±á¬á·á á
áá¬ážáá
ááºá ááŒáœááºážáá»ááºá ááá¯ááºááœááºááŸá¬ ááá¯ááºáá°ážá áá±á«áºááá¯ááŸá¯áá¯ááºá áááºážáá¯á¶áá²á· áááá«áá°áž (áá«á¡ááœáẠAppDomain.CurrentDomain.UnhandledException
á
áááºááŒáá·áº)á ááá¯á·ááŒá±á¬áá·áºá threads áá»á¬ážááœáẠerror handlers áá»á¬ážááá¯ááºááá¯ááºááŸáá·áº áááºáááºá
áœá¬ áááºá
á²ááŒááºážááŒáá·áº ááá¯á¡ááºáá«áááºá
á á¬ááŸá²ááá¯áž
á¡áá¯áá±á áá®ááááºááŸá±á¬ááºááŸá¯á áááºááœááºááŸá¯áá²á· áá±ááŒááºážááŒá¿áá¬ááᯠáááºááá¯ááŒá±ááŸááºážááá²á áá»áœááºá¯ááºááá¯á·ááẠáá¿áááá¬ááŸááºáá áºáŠážáááºážáᬠáááºážáá¯á¶áááºážááœááá¯á·áá±á¬ááºááŸáááẠááœáá·áºááŒá¯áááºááŒá áºááŒá®áž á€áá±áá¬á¡ááœáẠá¡ááŒááºá¡ááŸááºáá»ááºááŸááºáá¬ážáá±á¬ áá»ááºáá»áŸááºáá»á¬ážááᯠááá·áºáá«á áááºááᯠáá¯ááºáááá²? áá¿áááá¬ááŸááºáá áºáá±á¬ááºáá±á¬ááºááᯠáááºážááœá²ááá¯á· á á¬ážááœá²ááá¯ážáá áºáá±á¬ááºá ááœáá·áºáááŒá¯áá²á· áá¿áááá¬ááŸááºáá±ážááŸá¬ áááºáá±áááºááá¯áá«á áá¯á·á áá®á á¬ážááœá²ááá¯ážááᯠáá«ááá¯á·áááºááá¯áá¯ááºáááá²á áá¿áááá¬ááŸááºááœá±á áá°á·ááᯠáááºááá¯áá±ážááŒááá²ááá¯áá²á· áá±ážááœááºážááœá±á á áááºáááºá á¬ážá áá¬áá«á
á¡ááá¯ážááŸááºážáá¯á¶ážáááºážáááºážááŸá¬ áá¿áááá¬ááŸááºáá»á¬ážááẠáááºážáá¯á¶áááºážááœáá»á¬ážáá®ááá¯á· á á¬ážááœá²ááá¯ážá¡á¬áž á¡áááºáááŒááºáá±á¬ááºážááá¯áá±áá»áááºááŒá áºáááºá á¡á²áá«ááœá±á ááá¯á¡áá« áá¿áááá¬ááŸááºáá»á¬ážááẠá¡áá®ážáá¬ážááŸá áááºážááœá²áá áºáá¯ááᯠáá á±á¬áá·áºáá² á á¬ážááœá²ááá¯ážááᯠá á±á¬áá·áºááá¯ááºážáá±ááẠááŒá áºáááºá á¡á ááá¯ááºážááœááºá áá»áœááºá¯ááºááá¯á·ááẠáááºážá¡ááœáẠUser Space ááá¯áá¬á¡áá¯á¶ážááŒá¯áááºá áááºážááœáẠkernel á០áááºááá·áºáá¯ááºáá¯á¶ážáá¯ááºáááºážááá¯áááᯠáá±á«áºááẠááŒá¬ážááŒááºá¡áá¯á¶ážáááŒá¯áá« (á¡á±á¬ááºáá« áááºážááá¯á·á¡ááŒá±á¬ááºáž)á
á¡áá¯á¶ážááŒá¯áá°áá±áá¬ááŸá ááŒá±ááŸááºážáá»ááºáá»á¬áž
á€ááœáẠáá»áœááºá¯ááºááá¯á·ááẠáááºážáá¯á¶áááºážááœáá áºáá¯ááŸáá·áº áá¿áááááá¬ááŸáẠááŸá áºáŠážááá¯á· áá»áá·áºáá¯á¶ážáá²á·ááá·áºá¡ááá¯ááºáž áá»áœááºá¯ááºááá¯á· áá¯ááºáá±á¬ááºáááºááŒá áºááŒá®ážá áá»áœááºá¯ááºááá¯á·ááẠáá¶ááá¬áá áºáá¯ááœáẠááŸáá·áºáááºááŒá®áž á á±á¬áá·áºáá»áŸá±á¬áºáá±áá«áááºá ááá¯áá° áááºážááẠáá¿áááá¬ááŸááºá¡á¬ážáá¯á¶áž ááŒá áºáááá·áºáááºááŒá áºááŒá®ážá áááºážáá²á·ááá¯á·ááẠáááºážáá¯á¶áááºážááœáá áºáá¯áᬠááŒá áºáááºá á á¬ážááœá²ááá¯ážáá¶á០ဠâááœáŸá±áááºáááºážâ ááá¯áá°áá±á¬ áá¿áááá¬ááŸááºáá¬áá»áŸáẠá á¬ážáááá·áºáááºáᯠááá¯ááá¯ááºáááºá áááºážá¡ááœááºáá»áœááºá¯ááºááá¯á·ááẠ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
áá«á blocker áá
áºáá¯áá«á á¡ááŒááºážáá»ááºážááŒá±á¬áááẠá¡áá°áá°áá«áá²á while(true) { if (!lock) break; }
áá«áá±ááá·áº áááºáá±á¬áẠááá¯áá²á· "ááá¹á
áááº" áá²á· SpinWait
(á¡á²áá®ááŸá¬áá¯á¶ážáááºá ááᯠáá°á
á±á¬áá·áºááá¯ááºážáá±áá°áá»á¬ážááᯠáá±ááœááºáááºážá áá°ááá¯á·ááᯠáááºážáááºážá¡áááºááá¯ááºážááŒá®áž áá±á¬ááºáááºá¡áá¬áá»á¬ážááᯠáá°áááááºá á
áááºááá¯á·ááᯠáá±áá¯áá»á¡á¬ážááŒáá·áº optimize ááŒá
áºááá¯ááºááá»áŸ á¡áá¯ááºáá¯ááºáá±ážáááºá ááá¯á·áá±á¬áº áá¿áááááá¬ááŸááºáá
áºáŠážááẠá¡ááŒá¬ážáá°áá»á¬ážááẠááá¯ááŠážá
á¬ážáá±ážááŒá
áºáá¬áá±á¬áºáááºáž ááœáŸá±áááºážáá¯á¶ (Priority Inversion ááŒá¿áá¬) ááá«ááŸááá«á áááºážááẠáááá¯áááºáá¬á¡áááºážá¡ááŒá
áºáá»á¬ážááᯠá
á¬ážáá¯á¶ážááŒá®áž á
á®ážáááºážááŸá¯ááᯠááááºážááááºážáá±ážááá·áº áááºááŒáœáá±á¬áááºáááºááŸá¯áá¶ááá¬ááŸáá·áº á¡áá°áá°áááºááŒá
áºááŒá±á¬ááºáž áá»áœááºá¯ááºááá¯á· ááááááááºááŒá
áºáááºá . ááá¯á·ááŒá±á¬áá·áºá áá»áœááºá¯ááºááá¯á·ááẠááŒááºáááŸáá±á«áºááá¯ááŸá¯áá»á¬ážá nested locks ááŸáá·áº á¡ááŒá¬ážá¡á¶á·ááŒá
áá¬áá»á¬ážááá«áá² áá»áŸáá¯á¶ážááŸááºáá¬ááºááœáẠá¡ááœááºááá¯áá±á¬ááºážáá±á¬ááŒá±á¬ááºážáá²ááŸá¯áá»á¬ážá¡ááœááºáᬠá¡áá¯á¶ážááŒá¯áá«áááºá
áá¯á¶ááœá²ááá¯á· SpinLock
. á
ááºážáá»á±á¬ááºážáá»á¬ážááẠááœáŸá±áááºážáá¯á¶á¡ááœáẠá¡áááºáááŒáẠâááá¯ááºááœá²â ááŒá
áºáá±áááºá áá»ááºááœááºááŸá¯áá»á¬ážááŸáááẠ- áá¯á¶ááœááºá ááœá±ážáá»ááºáá¬ážáá±á¬á§áááá¬á cores áá»á¬ážááᯠá¡ááŒáá·áºá¡á á¡áá¯á¶ážáááŒá¯áá«- ဠthread áá±ážáá¯á០2/3 ááá·áºáá¬ááŸááááºá
á€áá±áá¬ááœáẠáá±á¬ááºáááºááŒá±ááŸááºážáá»ááºááŸá¬ á¡áá¯á¶ážááŒá¯áááºáá¬ááŒá
áºáááºá Interlocked.CompareExchange
á¡áááºáá¯ááºááœááºááŒáá¬ážááá·áºá¡ááá¯ááºáž áá°áá®áá±á¬áááºááŒáœá
áœá¬á
á±á¬áá·áºááá¯ááºážááŒááºážááŒáá·áº (áááºááœááºáá±á«ááºážáá«ážáá±á¬á¡ááœá±ážá¡áá±á«áºááá¬ááŸááºáá»á¬ážááœááº)á ááá¯á·áá±á¬áºá á€á¡áá¬ááẠáá®á¡áá¯áá®á¡áááááºááá¯á·ááŒááºážáá®ááá¯á· áŠážáááºááœá¬ážááá¯ááºáááºá
á¡áá±á«áº Interlocked
áááºáááºáááŸááááºááᯠáááááŒá¯ááá·áºáááºá CompareExchange
áá«áá±ááá·áº atomic read AND write á¡ááœáẠáááŒá¬ážáááºážáááºážááœá±áááºáž áá«áá«áááºá á¡ááŒá±á¬ááºážá¡áá²ááᯠáááºáá«ááá²áá²áá¯ááºááŒááºážááŒáá·áºá á¡ááŒá¬ážá
á¬ááœá²áá
áºáá¯ááẠáááºážáááŒá±á¬ááºážáá²ááŸá¯áá»á¬ážááá¯ááŒá¯áá¯ááºáááºá¡áá»áááºááŸááá»áŸáẠ(á ááá¯áááºáá«á áá áá±ážáá«á áá á
ᬠá ááẠááá±á¬ááºážáá«)á áááºážááᯠáááºááá¯ážáá
áºáá¯áááºážááá¯á· ááŸá¯ááºááœá±ážáá±á¬ááŒá±á¬ááºážáá²ááŸá¯áá»á¬ážá¡ááœáẠáá¯á¶ážááá¯ááºááẠ(Interlocked Anything pattern) .
Kernel áá¯ááºááŒá±ááŸááºážáá»ááº
á
ááºááá¯ááºážáá
áºáá¯ááœáẠá¡áááºážá¡ááŒá
áºáá»á¬ážááᯠááŒá¯ááºážáá®ážááŒááºážá០ááŸá±á¬ááºááŒááºáááºá ááŒáá¯ážáá
áºáá¯ááᯠáááºááá¯á·ááááºááá¯á·ááá¯ááºáááºááᯠááŒáá·áºááŒáá«á
áá¯á·á áá
áºáááºážááá¯ááá±á¬áº áá»áœááºá¯ááºááá¯á·áááá°áá¬ááá¯áááºá á
á¬ážááœá²ááá¯ážááẠáá¿áááá¬ááŸááºá¡á¬áž á¡áááºáá»á±á¬áºá
á±áááºááŸáá·áº ááá¯á¡ááºááá·áºá¡áá«ááŸáᬠááŸáá¯ážáá±ážáá¯á¶ááᯠááŒáá·áºááŒáá«á
áá¯á·á ááááŠážá
áœá¬á áááºáááºááŸá¯á
áá
áºá kernel áá¯ááºááŸáááá·áº áááºážááᯠáááºááá¯á·áá¯ááºáá±á¬ááºááááºááᯠááŒáá·áºááŒáá«á
áá¯á·á áááºáá±á¬ááºááŸá¯á¡á¬ážáá¯á¶ážááẠá¡áá¯á¶ážááŒá¯áá°áá±áá¬ááŸá áá»á¬ážááẠááŸá±ážááœá±ážáá±á·ááŸááááºá á¥ááá¬á¡á¬ážááŒáá·áº á¡ááŒáááºááŒáááºááŸá±ážááœá±ážáááºá AutoResetEvent
53 á ááá¯ááŸá±ážááá¯ááºáá«áááºá SpinLock
[ Richter ] ááá¯á·áá±á¬áº áááºážááá¯á·áá¡áá°á¡áá®ááŒáá·áºá áááºááẠá
áá
áºáá
áºáá»áŸá±á¬ááºáá¯á¶áž áá¯ááºáááºážá
ááºáá»á¬ážááᯠáá
áºááŒáá¯ááºáááºážáá¯ááºáá±á¬ááºááá¯ááºáááºá á
á®áá¶ááá·áºááœá²áááºááŒá
áºá
á± áááŒá¯áá¯ááºáá«á
á€áá±áá¬ááœáẠá¡ááŒá±áá¶áááºáá±á¬ááºáá¯á¶ááẠááœááºáá²á·áá±á¬ áá¬á
á¯ááŸá
áºáá
áºáááºáá»á±á¬áºá Dijkstra á០áááºááŒáá²á·áá±á¬ semaphore ááŒá
áºáááºá Semaphore ááá¯áááºááŸá¬ á
áá
áºá á
á®áá¶ááá·áºááœá²áá±á¬ á¡ááŒá¯ááá±á¬áá±á¬ááºáá±á¬ ááááºážááŒáá·áºááŒá
áºááŒá®áž áááºážááœáẠáá¯ááºáá±á¬ááºááŸá¯ ááŸá
áºáá¯á á¡ááá¯ážááŸáá·áº á¡áá»áŸá±á¬á·á¡áááºážááŸááááºá á¡áááºá áááºážááẠáá»áááºážááẠáá»ááºááœááºáá«á áá¯áá ááá¯á·áá±á¬áẠáá¯ááºážáá±á«áºááá¯ááŸá¯ááá¯ááºážááᯠááááºáá¬ážáááºá áá¶áá«ááºááᯠá¡ááŒá¬ážá¡áááºáááºáá±áá±á¬ thread/process á¡áá»áá¯á·á ááá¯ážáá¬áá±á¬á¡áá«á thread áá»á¬ážááᯠáá»á±á¬áºááœá¬ážáᬠsemaphore ááᯠáá»á±á¬áºááœááºááœá¬ážáá±á¬ á¡áá±á¡ááœááºá¡á¬ážááŒáá·áº áá
áºááẠáá»á±á¬á·áá»ááœá¬ážáá«áááºá semaphore ááŒáá·áº áá
áºááá¯á·áá±áá±á¬ ááá¬ážáá»á¬ážááᯠá
áááºáá°ážááŒáá·áºááá¯ááºáááºá .NET ááẠá¡áá¬ážáá° áá¯ááºáá±á¬ááºááá¯ááºá
áœááºážáá»á¬ážááŒáá·áº áááºáá±á¬ááºááŸá¯áá»á¬ážá
áœá¬ááᯠáá±ážáá±á¬ááºáááº- AutoResetEvent
, ManualResetEvent
, Mutex
áá«ááá¯ááºááá¯áẠSemaphore
. áá¯á¶ážáááºá AutoResetEvent
á€áááºáá±á¬ááºááŸá¯áá»á¬ážá á¡ááá¯ážááŸááºážáá¯á¶ážááŸá¬ 0 ááŸáá·áº 1 (falseá true) áááºááá¯ážááŸá
áºáá¯áá¬ááŒá
áºáááºá áá°áááááºážáááºáž 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
) ááá¯á·ááŒá
áºáá»áŸáẠáá¿áááá¬ááŸááºáá»á¬ážááẠáá®ááœááºáá°á¡á¬áž á
á±á¬áá·áºááá¯ááºážáá±áááá·áºáááºááŒá
áºáá±á¬ááŒá±á¬áá·áºá ááá¯ááá¯á·áá±á¬áá¯ááºáá»á¬ážááœáẠá¡ááŸá¬ážá¡ááœááºážáá»á¬ážááᯠááŸá¬ááœá±ááŒááºážááẠá¡ááœááºáááºáá²áá±á¬ á¡áá¯ááºááŒá
áºáááºá á€ááŒá±ááŸááºážáá»ááºááá±á¬ááºáááºááŒá¿áá¬ááŸá¬ ááœá±ážáá±á«áºááá¬ááŸááºá¡áá»áá¯á· ááá¯ááºáá¬áááºááá¯ááºááŒá±á¬ááºáž á¡á¬áááá¶ááá¯ááºáá«á
áá±á«ááºážá ááºááŒá±ááŸááºážáá»ááº
áá»áœááºá¯ááºááá¯á·ááẠá¡áá¯á¶ážááŒá¯áá°áá¯ááºááŸáá·áº á
ááºááá¯ááºážááœááºááŸááá±áá±á¬á¡áá«á ááŸáá·áº kernel ááŸáááá·áº thread ááá¯ááááºááá¯á·áá±á¬á¡áá«ááœáẠá¡áá»áááºááá¯ááºááẠáá»ááºážáááºááŸá¯ááŸá
áºáá¯ááᯠáá»áœááºá¯ááºááá¯á·ááŒáá·áºááŸá¯áá¬ážáá«áááºá ááááááºážáááºážááẠááá¯áá±á¬ááºážáá±á¬áá±á¬á·áááºááŒááºážá¡ááœáẠáá±á¬ááºážááœááºááŒá®áž áá¯ááááááºážáááºážááŸá¬ ááŸááºáá»á¬ážáá±á¬áá±á¬á·ááá±á¬ááºáá»á¬ážááŒá
áºáááºá ááœááºážáááºáá
áºáá¯ááœáẠááŒá±á¬ááºážáá²ááá¯ááºáá±á¬ ááááºážááŸááºáá
áºáá¯ááᯠá¡ááá¯áá»á¯á¶ážá
á±á¬áá·áºááá¯ááºážááẠáŠážá
áœá¬ ááá¯á¡ááºááŒá®áž á
á±á¬áá·áºááá¯ááºážááŸá¯ ááŒá¬áá¬áá±á¬á¡áá«ááœáẠthread ááᯠááááºááá¯á·ááẠááá¯á¡ááºáááºá áá®áá»ááºážáááºáááºážááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºáá¬ááá¯á· áá±á«áºáá«áááºá áá±á«ááºážá
ááºááœá²á·á
ááºážáá¯á¶áá»á¬ážá á€áááºááŸá¬ kernel áá¯ááºá¡ááœáẠáá°áá®áá±á¬áááºáá±á¬ááºáá¯á¶áá»á¬ážááŒá
áºáááºá ááá¯á·áá±á¬áº ááá¯á¡áá¯á¶ážááŒá¯áá°áá¯áẠloop áá
áºáá¯ááŒáá·áº SemaphorSlim
, ManualResetEventSlim
etc. áá®ááŸá¬ áá°ááŒáá¯ááºá¡áá»á¬ážáá¯á¶áž áá®ááá¯ááºážáá«á Monitor
, áá¬ááŒá
áºááá¯á·áá²ááá¯áá±á¬á· C# ááŸá¬ áá°áááá»á¬ážáá«áááºá lock
á¡áá¬ážá¡ááᯠMonitor
áááºážááẠá¡áá»á¬ážáá¯á¶ážáááºááá¯áž 1 (mutex) ááŸáá·áº áá°áá®áá±á¬áºáááºáž loop áá
áºáá¯ááœáẠá
á±á¬áá·áºááá¯ááºážáááºá recursioná 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
syntax ááœáẠááá¯ážááœá¬ážáá±á¬ á¡á¶á·ááŒááœááºáá¬áá»á¬ážááŸááááºá á¡áá¯á¶ážááŒá¯ááẠá¡ááŒá¶ááŒá¯á¡ááºáá«áááºá Monitor
ááá¯ááºááá¯áẠ[Richter] [Eric Lippert]á ááá±á¬ááºá á¡á²áá« lock
á¡ááŒá²áááºážááœáẠMonitor
ááŒáœááºážáá»ááºáá
áºáá¯ááŸááá»áŸááºáááºá á¡ááŒá¬ážá¡ááŒá±á¬ááºážá¡áá¬ááẠáá»áŸáá±áá¬ážáá±á¬ ááŸááºáá¬ááºá¡ááŒá±á¡áá±ááᯠááŒá±á¬ááºážáá²ááá¯ááºáááºá ááá¯ááá¯á·áá±á¬á¡ááŒá±á¡áá±áá»áá¯ážááœááºá áááŒá¬ááááááºááœá¬ážááŒááºáž ááá¯á·ááá¯áẠáááá¯ááááºááᯠáá¯á¶ááŒá¯á¶á
áœá¬ááááºáá
áºááŒááºážááẠáááŒá¬ááááá¯áááᯠááá¯áá±á¬ááºážáááºá áá±á¬ááºáááºá¡á¶á·á¡á¬ážááá·áºá
áá¬ááŸá¬ Monitor ááẠsynchronization áá¯ááºááœááºáá»á¬ážááá¯á¡áá¯á¶ážááŒá¯ááẠ(SyncBlock
á) á¡áá¬ááá¹áá¯á¡á¬ážáá¯á¶ážá áááºááŸáááŒááºážá ááá¯á·ááŒá±á¬áá·áºá áááá·áºáá»á±á¬áºáá±á¬ á¡áá¬áá
áºáá¯ááᯠááœá±ážáá»ááºáá«áá áááºááẠá¡ááœááºááá° áááááºááááá¯ááºááẠ(á¥ááá¬á áááºááá·áºááœááºážáá¬ážáá±á¬ á
á¬ááŒá±á¬ááºážáá
áºáá¯ááœáẠáá±á¬á·ááºáá»áá«á)á á€á¡ááœáẠáá»áœááºá¯ááºááá¯á·ááẠá¡ááŒá²áááºážááŸááºáá¬ážáá±á¬ á¡áá¬ááá¹áá¯ááᯠá¡áá¯á¶ážááŒá¯áááºá
Condition Variable áá¯á¶á á¶ááẠááá·áºá¡á¬áž ááŸá¯ááºááœá±ážáá±á¬á¡ááŒá±á¡áá±á¡áá»áá¯á·ááá»áŸá±á¬áºááá·áºáá»ááºááᯠááá¯ááá¯áááá»á áœá¬á¡áá±á¬ááºá¡áááºáá±á¬áºááá¯ááºá á±áá«áááºá .NET ááŸá¬á áááŒáá·áºá á¯á¶áá°áž ááá¯áá±á¬á· áá®á¡áá¯áá®á¡áá áá áºáá»áá¯ážáááºážááœááºááá¯ááºáá² ááááºážááŸááºáá»á¬ážá áœá¬ (Posix Threads áá²á·ááá¯á·) ááœáẠáááºážá á®ááŒááºážáá»á¬ážá áœá¬ááŸáááá·áºáááºá ááá¯á·áá±á¬áẠáá¿áááá¬ááŸááºá¡á¬ážáá¯á¶ážá¡ááœáẠáááºážááá¯á·ááᯠáááºáá®ážááá¯ááºáááºááŒá áºáááºá ááá¯á·áá±á¬áº á€áá¯á¶á á¶ááœááºáááºá áá¯ááºááᯠáá»áŸá±á¬á·áá»ááá¯ááºáááºá
áá¿áááá¬ááŸááºáá»á¬ážá
áœá¬ ááá¯á·ááá¯áẠasync
/ await
á¡áá¯áá±á ááᯠáá»áœááºá¯ááºááá¯á·ááẠá á¬ááœá²áá»á¬ážááᯠáááááá±á¬ááºáá±á¬áẠááááºááá¯á·ááá¯ááºáá«ááŒá®á ááá¯á·áá±á¬áº áá»áœááºá¯ááºááá¯á·ááœáẠáá¿áááá¬ááŸááºáá»á¬ážá áœá¬ááŸááá»áŸááºáá±á¬á 100? 10000? á¥ááá¬á¡á¬ážááŒáá·áºá áá»áœááºá¯ááºááá¯á·ááẠáááºáá¬áá¬ááá¯á· áá±á¬ááºážááá¯áá»áẠ100000 ááᯠáááºáá¶áááŸááá²á·áááºá áá±á¬ááºážááá¯ááŸá¯áá áºáá¯á á®á¡ááœáẠá á¬ááœá²áá áºáá¯áááºáá®ážáááºááŸá¬ áá±á«áºáá±áááºááŒá áºáá±á¬ááŒá±á¬áá·áºá á€áá»áŸáá±á¬ááºáá»á¬ážá áœá¬áá±á¬ threads áááºá¡ááŒáá¯ááºá¡áá¯ááºáá¯ááºáááºááá¯ááºáá«á logical cores áá»á¬ážááá±á¬ááºáᬠáááºáááºáá«ááẠ(áá«á·ááœáẠ4)á áááŒá¬ážáá°ááá¯ááºážá á¡áááºážá¡ááŒá áºááœá±ááᯠááááºážááœá¬ážáááá·áºáááºá á€ááŒá¿áá¬á¡ááœáẠá¡ááŒá±áá áºáá¯ááŸá¬ async/ait pattern ááŒá áºáááºá áááºážá á¡áá°á¡áááŸá¬ áááºážááẠáááºááẠáá áºáá¯áá¯ááᯠá á±á¬áá·áºááẠááá¯á¡ááºáá«á áá¯ááºáá±á¬ááºáá»ááºááẠthread ááᯠáááá¯ááºáá¬ážáá±á áá áºáá¯áá¯áá¯ááºáá±á¬á¡áá«á áááºážááẠáááºážá ááœááºáá»ááºááŸá¯ááᯠááŒááºáááºá áááºááẠ(ááá¯á·áá±á¬áº áá áºáá¯áááºážáá±á¬ thread ááœáẠáááá¯á¡ááºáá«á) áá«ááá¯á·ááá á¹á ááŸá¬á áá«ááá¯á·áááºážááœá²ááá¯á á±á¬áá·áºáááá·áºáááºá
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 ááŸáá·áº áááºáá¯ááºáá±á¬ááºááá¯ááºááá·áº á¡ááŒá¬ážá¡áá¬á¡á¬ážáá¯á¶ážááᯠá
á±á¬áá·áºááá¯ááºážááá¯ááºáááºá áááºážáááºážá¡ááœááºážááœááºá state machine ááẠáá¯ááºáá±á¬ááºááŸá¯ááᯠááááºážáá»á¯ááºáááºá á¡áááá¡áá»ááºááŸá¬ ááŸá±á¬áá·áºááŸá±ážááŒááºážáááŸááá«áá ááœááºáá»ááºááŸá¯ááẠáá
áºááŒáá¯ááºáááºáááºážááŒá
áºááŒá®áž ááŸááá»áŸáẠthread ááẠááœááºáá¬áááºááŒá
áºáááºá áá«ááᯠááá¯áá¬ážáááºááá¯á·á¡ááœáẠáá® state machine ááá¯ááŒáá·áºáᬠááá¯áá±á¬ááºážáá«áááºá á€á¡áá¬áá»á¬ážá០ááœááºážáááºáá»á¬ážááᯠáááºáááºáá®ážááá¯ááºáááºá async
/ await
áááºážáááºážáá»á¬ážá
á ááºážááŒáá·áºáá¡á±á¬ááºá ááœá±ážáá±á«áºááá¬ááŸáẠá¡áá±á¬áẠ100 ááẠáá¯áá¹áááá±á cores áá±ážáá¯áá«áá±á¬ á ááºáá áºáá¯áá±á«áºááœáẠ4 á áá¹ááá·áºááŒá¬ á¡áá¯ááºáá¯ááºáááºá Monitor ááŒáá·áº ááááºááŒá±ááŸááºážáá»ááºááẠáááá¡ááẠ8 áá¯áᬠáá¯ááºáá±á¬ááºáá²á·ááŒá®áž áá»ááºááẠáá¯á¶ážáááááºáááºáá«á á€á á¬ááœá² 4 áá¯á á®ááẠ4ms ááá·áº áááºáá¬ážáá¬ážáááºá ááŸáá·áº async/ait solution ááẠáá»ááºážáá»áŸ 2 á áá¹ááá·áºá á® á á±á¬áá·áºááá¯ááºážááŒááºážááŒáá·áº 100 áá¯á¶áž á¡áá¯ááºáá¯ááºáá«áááºá ááŸááºáá«áááºá á á áºááŸááºáá±á¬á áá áºáá»á¬ážááœáẠ6.8 á áá¹ááá·áºááŒá¬áá»áŸ áá»ááºážááááŒááºážááẠáááºáá¶ááá¯ááºááœááºáááŸáááá·áºá¡ááŒáẠá€áá²á·ááá¯á·áá±á¬ áá±á¬ááºážááá¯ááŸá¯áá»á¬ážááᯠááá¯ááºáá±á¬ááºááŒááºážááẠááá¯áá±á¬ááºážáá«áááºá Monitor ááŒáá·áºááŒá±ááŸááºážáá»ááºááẠá¡ááá¯ááºážá¡áá¬áá áºáá¯á¡áá áááŒá áºááá¯ááºáá±á¬á·áá±á
áá±á¬ááºáá»ááº
á€ááá°áá¬áááºáá»á¬ážá០áááºááœá±á·ááŒááºááá¯ááºáááºá¡ááá¯ááºážá .NET ááẠáááºáá°ááŒá¯ááŸá¯áááºáá±á¬ááºáá¯á¶áá»á¬ážá áœá¬ááᯠáá¶á·ááá¯ážáá±ážáá«áááºá ááá¯á·áá±á¬áº áááºážááá¯á·ááᯠáááºááá¯á·á¡áá¯á¶ážááŒá¯ááááºááᯠá¡ááŒá²ááááá¬áá±á áá®áá±á¬ááºážáá«ážá á¡áá±á¬ááºá¡áá°ááŒá áºáááºááá¯á· áá»áŸá±á¬áºááá·áºáá«áááºá ááá¯á¡áá»áááºááœááºá á€áááºááŸá¬ á¡áá¯á¶ážááŒá áºáááºá ááá¯á·áá±á¬áº á áááºáááºá á¬ážá áá¬áá»á¬ážá áœá¬ áá»ááºáá±áá±ážáááºá á¥ááá¬á thread-safe collectionsá TPL Dataflowá Reactive programmingá Software Transaction model á áááºááŒáá·áºá
ááááºážáááºážááŒá áº
- á
á®ážáááºážááŸá¯ááᯠáá¯á¶áá±á¬áºááŒááºáž-
Concurrency Visualizer - MSDN-
á¡ááœá¬ážá¡áᬠ,Asynchronous programming áá¯á¶á á¶áá»á¬áž ááŸáá·áºáá»á¬ážá áœá¬áá±á¬á¡ááŒá¬áž á¡ááŒá¬áž - [Richter] - C# ááŸáááá·áº CLRá Jeffrey Richter
- [Eric Lippert] -
áá±á¬á·áááºááŒááºážá¡ááŒá±á¬ááºáž á¡áááºážá¡ááŒá Ạ- áá¯ááºáá¯á¶ - "áá¬ážáá»á¬ážááŒá¬ážáá¡á", G. Semiradsky
source: www.habr.com