ααΌααααα‘ααααΎαααΈααααααααααααα·ααΈααααααααΆ αα·ααααΆαααΆα‘ααααααΎαααΆααα αααα»α .Net αααααααΎα§ααΆα ααααααααα αΆααααααα·ααΌα’αΆα αΆααααααααααα αααααΆααααααΆαααΌα ααΆαααααα ααΈααΆαααααΎααααΆααααααααααααα‘αΆα/ααααΎαααΆααα ααααΌαα½αααααα (αααα»ααααααααΆαααααα)α α’αααααα’αΆα ααΆααααααααααααααΆααα’αααααααΆααααααΆααααΌα α¬ααΎααααΈααααΎα±ααα ααααααΉαααααα’αααα‘αΎααα·αα
α ααα»α’αααΈααα ααααααΎαααααα? ααααααααΈααααααααα»αααΆααααααα αα’αααααααΆαααααα½ααα α αααΆαααααα Moore αααα»αααΆααααααααα·αααααααΏααααααΊ α αΎαααΌα ααααααΆαααΈαα ααααΎαααααΌαααΆαααααααααααΎαααΆα ααα½α ααααααααΈαααααααΆααααα αααΎαα’αΆα ααααΌαααΆαααααΎα‘αΎαα αααααΉαααΉααααααα·ααΆααα·αααααααααα»αααΎαα‘αΎα α αΎαα’αααααααΎααααΆααααααΉαααΆααΉαααΆαααΆαααααΎαααααααΆααααΈααααααααα αααα»αβααααΆαααΆαβαααβααα ααΆαβαααααβαααααα·ααΈ "ααααααΆ" αα βαααβαααβααΎαβααΆαβααααβαααα‘αΆαβααααα·ααααα·βαα½α αα·αβααΆαβααααα·αααααΆαβαααβααα ααΎαααααΌααααααααΆααααα αΆααααΆαααααα·ααααα·αααα»ααααααααΆαααααΆ α¬ααααααααΆα ααΎαααΈααααα ααααααα αΆαααααΆααα ααααα·αααααααααααΆ: αα ααααα·ααααααααα‘αΆααα ααααα·αααααΎαααΆααα ααααα·ααααΆαααΈααα ααΎαααααΆα (ααααααααα ααα αΆα) α .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
ααα»ααααααΆαα½αααΉαααΆαααΆααααα½ααααααααααααΆαα αααααααΆααααα»αααΆαα
αΆααααααΎααα·α
αα
ααΆααα½ααααααΆααααΈαα·α
αα
ααΆααααααα αααααΌααα½ααααααα·αααΈαα»αααΆα ααΆααααα½αααααΆααα½ααα αα·αα
αααΎααααα α ααΎαααΉααα·ααΆαα’αααΈααΏαααααα
ααααααααα
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 α
αα αααα»αααΌαααΆαααΆααααααααΆαααααααααα‘αΆα (ααΆααααΆαα) α ααααααααααα αΆαααΈααΆαααααα·ααααα· ααααααα ααααα αΆαααΈααΆαααααΎααααΆααααα α αΎαααααααααααααα αΆαααΆαααααααα‘αΆααααα»ααααα Diamonds αααα αΆαααΈαααααααΆα αΆααααααΎααα Tasks α
ααΆααααααααααΆαααααααααα·ααΌ
αααααΈααΆα’ααααα·αααααΌαααΆαα’αΆα αΆαα αααΎαααΎααααΈαα·αααααα ααΆααααααααααΆαα’αΆα αααααααααΆααααΆααα±ααααααααααααααα·ααααΆα α αΌαααΎαααααΆααΆααααααααααΎααααΆαααΆαααααΆαα’ααααααΆααααααααα‘αΆααα αααα»ααααα αΆααααααΎαα ααΆαα’ααααααΆαααΊαα ααααααα’ααααααααΎαααΆα ααα»ααααααΎααααΆαααΆαααΆαααααΆαααα αααααΆααα·αααα ααΆααΊααΆααΆαααΆααααΆααααΌα ααααΆ ααΆαααααααααααααααααα·αααααα ααα»αααααααα»αααααααααααααααΆααααΆαααααα ααα»αααααα·αααΆαα’αΆα αΆαα ααΎααααΈαααααΆαααΆαααααααΉαααΆαα ααΎαααΉαααΆαααααααα·α ααααα·αααΎααΎααα·αα’αΆα αααα½αααααααααα
// Π’ΠΎ ΠΆΠ΅ ΡΡΠΎ ΠΈ Π² 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 ααΊα’αΆααααα) ααΆα’αΆα
ααααΌαααΆαααααΎαααααΆααααΆαααααΆααααααΌααααα»αααααααΆααα
ααΉαααααααα½α (ααααΆαα’ααααααααααΆαα½α) α
αααααααααΆαααααααΊααα
ααΎααααΈαααααΆαααΆαααααααααΆαααααΆααα
αααα»αααααα·ααα»ααα½α ααΌαααΎαααΈααααααΎααααΈααΆααΆαααααααααα‘αΆαα αααααΆαααα ααΆαααααα§ααΆα αααααααααΎα ααΌαααΎαααΈαααααααα’αααααααα»ααΆααααααααα·ααΌα±ααααα α αΎαααΆααααΆααα±ααααααΆαααααααα
αΆαααΆα
αααα»αααααα ααΆααααΌα ααΌααααα‘ααααΎαααααααααΎααΆααΆααααααααααΊαααααααααααααααααα·ααααα·ααΆαα αα
ααΆααααααααααΆααα’αααα
ααΈαααα
αααΎααααααα
ααααΊαααΆαααααααααααΎααααΆααα ααΊαα
αααΎααα ααΆα§ααΆα ααα AutoResetEvent
αααα ααααΆ 53 ααααΊαααΆα SpinLock
[αα·α
ααα] α ααα»αααααααααΆααααα½ααααααα½ααα α’αααα’αΆα
ααααΎααααΆαααααααααΎαααΆααα
ααΌααΆααααααααααααΆααααΌα αααααααααα¬α’ααα
ααΆααα
ααΆααΆααΌαααααΆααα
ααΈαααααΊααΆ semaphore αααααααΎα‘αΎαααα Dijkstra ααΆαααααααααααααα»αα Semaphore ααΊαα·ααΆααααααΆααααααΆ α
ααα½αααααα·αααααΆαααααααααααααααααααααααα αα·αααααα·ααααα·ααΆαααΈααα
ααΎααΆ - αααααΎα αα·ααααααα ααααα·αααΎαα·αα’αΆα
ααΆαααααααααΌαααααΆαααααα ααααααΌααααααααααΌαααΆαααΆααΆααα αα
ααααααα
ααα½αααααΌαααΆαααΎαα‘αΎαααααααααααα‘αΆα/ααααΎαααΆαααααααα½αα
ααα½ααααααααα ααααααααααα‘αΆαααααΌαααΆαααααααΆαα α αΎα semaphore ααααΌαααΆαααΆαααααααααααααααααα
ααα½ααααααΆαααααααΆααα α’αααβα’αΆα
βαααααβααΎαβααααααΎαβαα
βαααα»αβααΆαβααααααβααΆαα½αβααΉαβαααααΆβαααααΆααα .NET αααααααΌααααααααΆα
αααΎααααααΆααα»αααΆαααααααααααΆα AutoResetEvent
, ManualResetEvent
, Mutex
αα·ααααα½ααααα»αααααΆαα Semaphore
. ααΎαααΉαααααΎ AutoResetEvent
αααβααΊβααΆβααΆαβααΆααααβαααα»αβααβααΆαβααΆαβαααβααΆααβαααα ααΆαβααβαααααβααΈα α αα·α α‘ (αα·αβαα·α αα·α)α αα·ααΈααΆαααααααααααΆα WaitOne()
ααΆααΆααβααααβααΆαβα α
βααΌααααα ααααα·αααΎβαααααβααΊ 0 α αΎαβααααα·αααΎ 1 αααβαααααΆααβααΆβαα
0 α αΎαβααααβααΆα αα·ααΈααΆααααααα½αα Set()
ααΎαα‘αΎαααα 1 αα·αα’αα»ααααΆαα±ααααα»αααααααΆααααααααΆαα αααααααααααααααααααααΉα 0α ααααΎαααααααΆαααΌα
ααΆ turnstile αα
αααα»αααααααΎααααααααΈα
α αΌαααααΎα±αααααα»αααααΆαααααααααααααΆα α αΎαααααΎααΆααααααααΆαααααααΆααααααααα·ααΌααααΆααα α αΎααα·αααααααααΆααααΆααα’ααααααΆαααα»αααααααα½ααααααα ααΆαααααα α₯α‘αΌαβααα ααααααα·ααΌβααΆα αααΎαβα’αΆα βαααΆαβαααα»αααααααα½α α αΎαβαα·ααααβαααα½αβαα»αβααα ααα»αααα ααΎαβαα·αβααΆαβα αΌαβαα βαα»βααααβααα ααΎααααΈβααβααβααΆαβααααΉαβααααΌα αααααΆαβααααααααβααΆαβαααααΆααα
// ΠΠ»Ρ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠΈΠ»ΠΎΡΠΎΡΠ°.
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΡΡΡ: 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
αααααΊααΆ semaphore ααΌα
ααααΆααΆαα½αααΉααααααα’αα·ααααΆαα 1 (mutex) ααα»ααααααΆαα½αααΉαααΆαααΆαααααααααΆααααΆααααα
αΆααα
αααα»αααααα·ααα»α ααΆααααααΎαα‘αΎααα·α ααααααααα’αααααααΆα (α
αααΎαααααα
ααΎαααααΆαααααα) ααα ααΌααααα‘ααααΎααααααααααΆαααΆαα½αααΆα
// Π‘ΠΏΡΡΡΠ΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡ Π΄Π»Ρ ΠΠΎΠ½ΠΈΡΠΎΡΠ° ΠΎΡ Π²ΡΠ΅Ρ
, ΡΡΠΎΠ±Ρ Π±Π΅Π· Π΄Π΅Π΄Π»ΠΎΠΊΠΎΠ².
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
αααααααΆαα [Richter] [Eric Lippert] α αα½ααααα»αα
αααααα½αααααΊαααα lock
αααααα
αααα Monitor
αααααΈααΆααΆαααααΈααΎαααααα½α α αΎααααααΆαααα ααααααααααααα’αΆα
ααααΆααααααΌαααααΆαααΆαααα’αααα
αα
αΆααααααΆαα
αααααααα αααα»αααααΈαααααα ααΆααΆααΆααααααΎααααα»αααΆαα
αΌααα
αααα»αααΆαααΆααααΆαα α¬αααα
αααααααα·ααΈααααα»ααααα·ααΆαα ααΆαααααΆααααα’αΎααα½ααααααΊααΆαααΌααΈαααααααΎαααα»αααΆα‘α·ααΆ (SyncBlock
) αααααΆααα
αααα»αααααα»ααΆααα’ααα ααΌα
αααα ααααα·αααΎααααα»αα·ααααααααα½αααααΌαααΆαααααΎαααΎα α’αααα’αΆα
ααα½αααΆαααΆαααΆααααΆααααΆααααΆαααΆααααα½α (α§ααΆα ααα ααααα·αααΎα’αααα
αΆαααααα
ααΎααααα’αααααααααααΎαααΆα)α ααΎααααααααααΎααααα»ααΆαααααααΆααααΏααααα
ααααΆαα’αααααααααααα’αα»ααααΆαα±ααα’αααα’αα»ααααααΆαααααΉααα»ααααααααααααααα»αααααΆααα½αα ααα½αα αα αααα»α .NET ααΆαα·ααααααααα ααΆααααα·ααααααααα»α ααααα... ααΆαααααΉααααΈ αα½αααααΆααα½αααΆα αααΎααα ααΎα’αααααΆα αααΎα (ααΌα αα αααα»α Posix Threads) α αΎααα·αααααα ααΎαααααα½αααα αααααΆααααααΆααΉαα’αΆα ααααΎαα ααΆαααΎααααΈααααΎα±αααα½ααααααααΆααααααααα·ααΌααΆααα’ααα ααα»ααααααΌααααΈαααα αααα»ααααααααααααΆα’αα»ααααΆαα±ααα’αααααααΈααΌαα
ααααααα·ααΌααΆα
αααΎαα¬ async
/ await
αα·αα’αΈαα α₯α‘αΌααααααΎαα’αΆα αααααααΆαααααααααα‘αΆαααΆααααΆαααΆαααααα·αααααΆαα ααα»αααα α α»αβααΎβααΎαβααΆαβααααααα·ααΌβα αααΎα? 100? 10000? α§ααΆα ααα ααΎαααΆαααα½αααααΎ 100000 αα ααΆαααααΆαααΈαααααα αααααα ααΆααααααΎααααααααα‘αΆααααααΆααααααΎααΈαα½ααααΉαααΆααααααααααααααα ααΌα αααα αααααααα‘αΆαααΆα αααΎαααΉααα·αααααΌαααΆαααααα·ααααα·ααααααααΆααα ααΆαααααααΌαα‘αΌααΈααααΆα αααΎαααα»ααααααααααΉαααααΌαααΆαααααα·ααααα· (αααα»αααΆα 4) α α αΎαα’αααααααααααααΉαααααΆααααααααααΆαα αααααααααΆααα½αα αααααααα αΆαααααΊααααΆα async/await α αααα·αααααααΆααΊααΆαα»αααΆααα½ααα·αααΆαααααααααα‘αΆαααααααα·αααΎααΆααααΌαααΆααααα αΆαα’αααΈαα½αααΎααααΈααααα α αΎααα ααααααααΆαα’αααΈαα½αααΎαα‘αΎα ααΆααααααΆαααααα·ααααα·ααααααΆα‘αΎααα·α (ααα»αααααα·αα αΆαααΆα ααα αααα»ααααααααα‘αΆαααΌα ααααΆαα!) αααα»αααααΈααααααΎα ααΎαααΉααααα αΆαααααΌααα½α
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 threads ααααΌαααα»ααααα α αΎααα·αααΆαααααα·ααααα·α’αααΈααααα αααααΆαααααααα αααααααααΆαααΆαα 4 ααΈαα½ααααααΌαααΆααα»αα αααααα αα 2ms α α αΎααααααααααΆα async/await ααΆαααααΎααΆααα’αα 100 αααααΆααααα 6.8 αα·ααΆααΈααΆααααΆααααα αΆαα ααΆααΆααα·αααΆαα αα αααα»ααααααααααα·α ααΆααα ααααααααααα 6 αα·ααΆααΈααΊαα·αα’αΆα ααα½αααααΆααα α αΎαααΆααΆααΆααααααΎαααΆααα»αααααΎαααΆαααααΎααΆα αααΎαααΆααα·ααΈαααα αααααααααΆαααΆαα½α Monitor ααααααΆαα·αα’αΆα ααααΎααΆαααααααΆαααΆαααΆαααααααα
ααα ααααΈααααα·ααααΆα
ααΌα αααα’αααα’αΆα ααΎαααΎαααΈα§ααΆα αααααΌα αααΆααααα .NET ααΆααααααΆααααααΎαααααΆαααααααΆα αααΎαα ααααααΆαααΆααααα ααΆαα·ααααααα αααΆααα’αααΈααααααααΎαα½αααΆαααααα αααα»ααααααΉαααΆα’ααααααααααΆαααααααααα ααΎαβαααα»αβαααα ααβααΆβαααααΆααβαααβααα ααα»ααααβααΆβαα βααΆαβααααα»βαα½αβα±ααβα αΆααβα’αΆααααααβααΆβα αααΎαβαααβαα βααααααβα§ααΆα ααα ααΆαβαααααΌαβαα»ααααα·ααΆαβααααβαααααΆα TPL Dataflow ααΆαβαααααβαααααα·ααΈβααααα·αααα ααααΌβααααα·ααααα·ααΆαβαααααα·ααΈβααΆααΎαα
αααααα
- ααΆαααΎαααΎαααα αΌαα
αααααα·ααΈααΎαααΎαααααααααΆα - MSDNα
αααααα‘αΆα ,ααααΆαααααααααααα·ααΈα’ααααΆα αα·αα αααΎαααα αα - [Richter] β CLR ααΆαααα C#, Jeffrey Richter
- [Eric Lippert] -
α’αααΈααΆαα αΆαααα ααααα - ααΌαααΆα - "ααΆααααα»αα ααααααΆα", G. Semiradsky
ααααα: www.habr.com