Π”ΠΎΠ±Ρ€Π΅ ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈ философи ΠΈΠ»ΠΈ ΡΡŠΡΡ‚Π΅Π·Π°Ρ‚Π΅Π»Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅ Π² .NET

Π”ΠΎΠ±Ρ€Π΅ ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈ философи ΠΈΠ»ΠΈ ΡΡŠΡΡ‚Π΅Π·Π°Ρ‚Π΅Π»Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅ Π² .NET

НСка Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΊΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚ΠΈ Π΅Π΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΡ‚ΠΎ ΠΈ ΠΏΠ°Ρ€Π°Π»Π΅Π»Π½ΠΎΡ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅ Π² .Net, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π½Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° с обядващитС философи. ΠŸΠ»Π°Π½ΡŠΡ‚ Π΅ слСдният, ΠΎΡ‚ синхронизиранСто Π½Π° ΠΏΠΎΡ‚ΠΎΠΊ/процСс Π΄ΠΎ ΠΌΠΎΠ΄Π΅Π»Π° Π½Π° Π°ΠΊΡ‚ΡŒΠΎΡ€Π° (Π² слСдващитС части). Бтатията ΠΌΠΎΠΆΠ΅ Π΄Π° Π΅ ΠΏΠΎΠ»Π΅Π·Π½Π° Π·Π° ΠΏΡŠΡ€Π²ΠΎ запознанство ΠΈΠ»ΠΈ Π·Π° опрСсняванС Π½Π° знанията.

Π—Π°Ρ‰ΠΎ ΠΈΠ·ΠΎΠ±Ρ‰ΠΎ Π΄Π° Π·Π½Π°Π΅Ρ‚Π΅ ΠΊΠ°ΠΊ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ Ρ‚ΠΎΠ²Π°? ВранзисторитС достигат минималния си Ρ€Π°Π·ΠΌΠ΅Ρ€, Π·Π°ΠΊΠΎΠ½ΡŠΡ‚ Π½Π° ΠœΡƒΡ€ достига Π³Ρ€Π°Π½ΠΈΡ†Π°Ρ‚Π° Π½Π° скоростта Π½Π° свСтлината ΠΈ слСдоватСлно сС наблюдава нарастванС Π½Π° броя; ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° сС правят ΠΏΠΎΠ²Π΅Ρ‡Π΅ транзистори. Π’ ΡΡŠΡ‰ΠΎΡ‚ΠΎ Π²Ρ€Π΅ΠΌΠ΅ количСството Π΄Π°Π½Π½ΠΈ растС ΠΈ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΠΈΡ‚Π΅ ΠΎΡ‡Π°ΠΊΠ²Π°Ρ‚ Π½Π΅Π·Π°Π±Π°Π²Π΅Π½ ΠΎΡ‚Π³ΠΎΠ²ΠΎΡ€ ΠΎΡ‚ систСмитС. Π’ Ρ‚Π°ΠΊΠ°Π²Π° ситуация β€žΠ½ΠΎΡ€ΠΌΠ°Π»Π½ΠΎΡ‚ΠΎβ€œ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅, ΠΊΠΎΠ³Π°Ρ‚ΠΎ ΠΈΠΌΠ°ΠΌΠ΅ Π΅Π΄Π½Π° ΠΈΠ·ΠΏΡŠΠ»Π½ΡΠ²Π°Ρ‰Π° нишка, Π²Π΅Ρ‡Π΅ Π½Π΅ Π΅ Π΅Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ. Врябва ΠΏΠΎ някакъв Π½Π°Ρ‡ΠΈΠ½ Π΄Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΠΌ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° с Π΅Π΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΡ‚ΠΎ ΠΈΠ»ΠΈ ΠΏΠ°Ρ€Π°Π»Π΅Π»Π½ΠΎ изпълнСниС. ОсвСн Ρ‚ΠΎΠ²Π° Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ ΡΡŠΡ‰Π΅ΡΡ‚Π²ΡƒΠ²Π° Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ Π½ΠΈΠ²Π°: Π½Π° Π½ΠΈΠ²ΠΎ нишка, Π½Π° Π½ΠΈΠ²ΠΎ процСс, Π½Π° Π½ΠΈΠ²ΠΎ машини Π² ΠΌΡ€Π΅ΠΆΠ°Ρ‚Π° (Ρ€Π°Π·ΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ систСми). .NET ΠΈΠΌΠ° висококачСствСни, ΠΈΠ·ΠΏΠΈΡ‚Π°Π½ΠΈ във Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ Π·Π° Π±ΡŠΡ€Π·ΠΎ ΠΈ Π΅Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ Ρ€Π΅ΡˆΠ°Π²Π°Π½Π΅ Π½Π° ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ.

Π—Π°Π΄Π°Ρ‡Π°

ЕдсгСр ДСйкстра Π·Π°Π΄Π°Π²Π° Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Π½Π° своитС ΡƒΡ‡Π΅Π½ΠΈΡ†ΠΈ ΠΏΡ€Π΅Π· 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, Π½ΠΎ с всякакви удобства: Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ Π·Π° стартиранС Π½Π° Π·Π°Π΄Π°Ρ‡Π° слСд Π±Π»ΠΎΠΊ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ, Π²Ρ€ΡŠΡ‰Π°Π½Π΅Ρ‚ΠΎ ΠΈΠΌ ΠΎΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΡƒΠ΄ΠΎΠ±Π½ΠΎΡ‚ΠΎ ΠΈΠΌ ΠΏΡ€Π΅ΠΊΡŠΡΠ²Π°Π½Π΅ ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ Π΄Ρ€ΡƒΠ³ΠΈ. ΠΈ Ρ‚.Π½. Π’Π΅ са Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈ Π·Π° ΠΏΠΎΠ΄Π΄ΡŠΡ€ΠΆΠ°Π½Π΅ Π½Π° конструкции async/await (асинхронСн ΠΌΠΎΠ΄Π΅Π», Π±Π°Π·ΠΈΡ€Π°Π½ Π½Π° Π·Π°Π΄Π°Ρ‡ΠΈ, синтактична Π·Π°Ρ…Π°Ρ€ Π·Π° ΠΈΠ·Ρ‡Π°ΠΊΠ²Π°Π½Π΅ Π½Π° IO ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ). Π©Π΅ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ Π·Π° Ρ‚ΠΎΠ²Π° ΠΏΠΎ-късно.

CancelationTokenSource Ρ‚ΡƒΠΊ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π½ΠΈΡˆΠΊΠ°Ρ‚Π° Π΄Π° ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‚ΠΈ ΠΏΡ€ΠΈ сигнал ΠΎΡ‚ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Ρ‰Π°Ρ‚Π° нишка.

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ със синхронизиранСто

Π‘Π»ΠΎΠΊΠΈΡ€Π°Π½ΠΈ философи

Π”ΠΎΠ±Ρ€Π΅, Π·Π½Π°Π΅ΠΌ ΠΊΠ°ΠΊ Π΄Π° създавамС Ρ‚Π΅ΠΌΠΈ, Π½Π΅ΠΊΠ° ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ обяд:

// ΠšΡ‚ΠΎ ΠΊΠ°ΠΊΠΈΠ΅ Π²ΠΈΠ»ΠΊΠΈ взял. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ: 1 1 3 3 - 1ΠΉ ΠΈ 3ΠΉ взяли ΠΏΠ΅Ρ€Π²Ρ‹Π΅ Π΄Π²Π΅ ΠΏΠ°Ρ€Ρ‹.
private int[] forks = Enumerable.Repeat(0, philosophersAmount).ToArray();

// Π’ΠΎ ΠΆΠ΅, Ρ‡Ρ‚ΠΎ RunPhilosopher()
private void RunDeadlock(int i, CancellationToken token) 
{
    // Π–Π΄Π°Ρ‚ΡŒ Π²ΠΈΠ»ΠΊΡƒ, Π²Π·ΡΡ‚ΡŒ Π΅Ρ‘. Π­ΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½Ρ‚Π½ΠΎ: 
    // while(true) 
    //     if forks[fork] == 0 
    //          forks[fork] = i+1
    //          break
    //     Thread.Sleep() ΠΈΠ»ΠΈ Yield() ΠΈΠ»ΠΈ SpinWait()
    void TakeFork(int fork) =>
        SpinWait.SpinUntil(() => 
            Interlocked.CompareExchange(ref forks[fork], i+1, 0) == 0);

    // Для простоты, Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ с Interlocked.Exchange:
    void PutFork(int fork) => forks[fork] = 0;

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

        // Π—Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΏΠΎ-Ρ…ΠΎΡ€ΠΎΡˆΠ΅ΠΌΡƒ.
        token.ThrowIfCancellationRequested();
    }
}

Π’ΡƒΠΊ ΠΏΡŠΡ€Π²ΠΎ сС ΠΎΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π΄Π° Π²Π·Π΅ΠΌΠ΅ΠΌ лявата, Π° слСд Ρ‚ΠΎΠ²Π° дясната Π²ΠΈΠ»ΠΈΡ†Π° ΠΈ Π°ΠΊΠΎ сС ΠΏΠΎΠ»ΡƒΡ‡ΠΈ, ядСм ΠΈ Π³ΠΈ Π²Ρ€ΡŠΡ‰Π°ΠΌΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ. Π’Π·Π΅ΠΌΠ°Π½Π΅Ρ‚ΠΎ Π½Π° Π΅Π΄Π½Π° Π²ΠΈΠ»ΠΈΡ†Π° Π΅ Π°Ρ‚ΠΎΠΌΠ½ΠΎ, Ρ‚.Π΅. Π΄Π²Π΅ нишки Π½Π΅ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° ΠΏΡ€ΠΈΠ΅ΠΌΠ°Ρ‚ Π΅Π΄Π½Π° Π΅Π΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ (Π³Ρ€Π΅ΡˆΠ½ΠΎ: ΠΏΡŠΡ€Π²Π°Ρ‚Π° Ρ‡Π΅Ρ‚Π΅, Ρ‡Π΅ Ρ„ΠΎΡ€ΠΊΡŠΡ‚ Π΅ свободСн, Π²Ρ‚ΠΎΡ€Π°Ρ‚Π° ΠΏΡ€Π°Π²ΠΈ ΡΡŠΡ‰ΠΎΡ‚ΠΎ, ΠΏΡŠΡ€Π²Π°Ρ‚Π° Π²Π·Π΅ΠΌΠ°, Π²Ρ‚ΠΎΡ€Π°Ρ‚Π° Π²Π·Π΅ΠΌΠ°). Π—Π° Ρ‚ΠΎΠ²Π° Interlocked.CompareExchange, ΠΊΠΎΠ΅Ρ‚ΠΎ трябва Π΄Π° сС Ρ€Π΅Π°Π»ΠΈΠ·ΠΈΡ€Π° с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° инструкция Π½Π° процСсора (TSL, XCHG), ΠΊΠΎΠΉΡ‚ΠΎ Π·Π°ΠΊΠ»ΡŽΡ‡Π²Π° част ΠΎΡ‚ ΠΏΠ°ΠΌΠ΅Ρ‚Ρ‚Π° Π·Π° Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎ послСдоватСлно Ρ‡Π΅Ρ‚Π΅Π½Π΅ ΠΈ запис. И SpinWait Π΅ Π΅ΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½Ρ‚Π΅Π½ Π½Π° конструкцията while(true) само с ΠΌΠ°Π»ΠΊΠΎ β€žΠΌΠ°Π³ΠΈΡβ€œ - Π½ΠΈΡˆΠΊΠ°Ρ‚Π° Π·Π°Π΅ΠΌΠ° процСсора (Thread.SpinWait), Π½ΠΎ понякога ΠΏΡ€Π΅Π΄Π°Π²Π° ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π° Π½Π° Π΄Ρ€ΡƒΠ³Π° нишка (Thread.Yeild) ΠΈΠ»ΠΈ заспива (Thread.Sleep).

Но Ρ‚ΠΎΠ²Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π½Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ, Π·Π°Ρ‰ΠΎΡ‚ΠΎ... Π½ΠΈΡˆΠΊΠΈΡ‚Π΅ скоро (Π² Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° сСкунда Π·Π° ΠΌΠ΅Π½) са Π±Π»ΠΎΠΊΠΈΡ€Π°Π½ΠΈ: всички философи ΠΏΠΎΠ΅ΠΌΠ°Ρ‚ лявото си Ρ€Π°Π·ΠΊΠ»ΠΎΠ½Π΅Π½ΠΈΠ΅, Π½ΠΎ няма дясно. Π’ΠΎΠ³Π°Π²Π° ΠΌΠ°ΡΠΈΠ²ΡŠΡ‚ forks ΠΈΠΌΠ° стойноститС: 1 2 3 4 5.

Π”ΠΎΠ±Ρ€Π΅ ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈ философи ΠΈΠ»ΠΈ ΡΡŠΡΡ‚Π΅Π·Π°Ρ‚Π΅Π»Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅ Π² .NET

На снимката Π±Π»ΠΎΠΊΠΈΡ€Π°Π½Π΅ Π½Π° нишки (Π±Π΅Π·ΠΈΠ·Ρ…ΠΎΠ΄ΠΈΡ†Π°). Π—Π΅Π»Π΅Π½ΠΎΡ‚ΠΎ ΠΏΠΎΠΊΠ°Π·Π²Π° изпълнСниС, Ρ‡Π΅Ρ€Π²Π΅Π½ΠΎΡ‚ΠΎ ΠΏΠΎΠΊΠ°Π·Π²Π° синхронизация, Π° сивото ΠΏΠΎΠΊΠ°Π·Π²Π°, Ρ‡Π΅ Π½ΠΈΡˆΠΊΠ°Ρ‚Π° спи. Π”ΠΈΠ°ΠΌΠ°Π½Ρ‚ΠΈΡ‚Π΅ ΠΏΠΎΠΊΠ°Π·Π²Π°Ρ‚ Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π·Π° стартиранС Π½Π° Π·Π°Π΄Π°Ρ‡ΠΈΡ‚Π΅.

Π“Π»Π°Π΄ΡŠΡ‚ Π½Π° философитС

Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‡Π΅ Π½Π΅ сС Π½ΡƒΠΆΠ΄Π°Π΅Ρ‚Π΅ ΠΎΡ‚ ΠΌΠ½ΠΎΠ³ΠΎ Ρ…Ρ€Π°Π½Π°, Π·Π° Π΄Π° мислитС, Π³Π»Π°Π΄ΡŠΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΡ€ΠΈΠ½ΡƒΠ΄ΠΈ всСки Π΄Π° сС ΠΎΡ‚ΠΊΠ°ΠΆΠ΅ ΠΎΡ‚ философията. НСка сС ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° симулирамС ситуацията Π½Π° Π³Π»Π°Π΄ΡƒΠ²Π°Π½Π΅ Π½Π° нишка Π² нашия ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ. Π“Π»Π°Π΄ΡŠΡ‚ Π΅, ΠΊΠΎΠ³Π°Ρ‚ΠΎ Π΅Π΄Π½Π° нишка Ρ€Π°Π±ΠΎΡ‚ΠΈ, Π½ΠΎ Π±Π΅Π· Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½Π° Ρ€Π°Π±ΠΎΡ‚Π°, с Π΄Ρ€ΡƒΠ³ΠΈ Π΄ΡƒΠΌΠΈ, Ρ‚ΠΎΠ²Π° Π΅ ΡΡŠΡ‰Π°Ρ‚Π° Π±Π΅Π·ΠΈΠ·Ρ…ΠΎΠ΄ΠΈΡ†Π°, само сСга Π½ΠΈΡˆΠΊΠ°Ρ‚Π° Π½Π΅ спи, Π° Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ Ρ‚ΡŠΡ€ΡΠΈ Π½Π΅Ρ‰ΠΎ Π·Π° ядСнС, Π½ΠΎ няма Ρ…Ρ€Π°Π½Π°. Π—Π° Π΄Π° ΠΈΠ·Π±Π΅Π³Π½Π΅ΠΌ чСсто Π±Π»ΠΎΠΊΠΈΡ€Π°Π½Π΅, Ρ‰Π΅ Π²ΡŠΡ€Π½Π΅ΠΌ Π²ΠΈΠ»ΠΈΡ†Π°Ρ‚Π° ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ, Π°ΠΊΠΎ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Π²Π·Π΅ΠΌΠ΅ΠΌ Π΄Ρ€ΡƒΠ³Π°.

// Π’ΠΎ ΠΆΠ΅ Ρ‡Ρ‚ΠΎ ΠΈ Π² RunDeadlock, Π½ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΊΠ»Π°Π΄Π΅ΠΌ Π²ΠΈΠ»ΠΊΡƒ Π½Π°Π·Π°Π΄ ΠΈ добавляСм ΠΏΠ»ΠΎΡ…ΠΈΡ… философов.
private void RunStarvation(int i, CancellationToken token)
{
    while (true)
    {
        bool hasTwoForks = false;
        var waitTime = TimeSpan.FromMilliseconds(50);
        // ΠŸΠ»ΠΎΡ…ΠΎΠΉ философов ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΠΆΠ΅ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΈΠ»ΠΊΡƒ:
        bool hasLeft = forks[Left(i)] == i + 1;
        if (hasLeft || TakeFork(Left(i), i + 1, waitTime))
        {
            if (TakeFork(Right(i), i + 1, TimeSpan.Zero))
                hasTwoForks = true;
            else
                PutFork(Left(i)); // Иногда ΠΏΠ»ΠΎΡ…ΠΎΠΉ философ ΠΎΡ‚Π΄Π°Π΅Ρ‚ Π²ΠΈΠ»ΠΊΡƒ Π½Π°Π·Π°Π΄.
        } 
        if (!hasTwoForks)
        {
            if (token.IsCancellationRequested) break;
            continue;
        }
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        bool goodPhilosopher = i % 2 == 0;
        // А ΠΏΠ»ΠΎΡ…ΠΎΠΉ философ Π·Π°Π±Ρ‹Π²Π°Π΅Ρ‚ ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚ΡŒ свою Π²ΠΈΠ»ΠΊΡƒ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ:
        if (goodPhilosopher)
            PutFork(Left(i));
        // А Ссли ΠΈ ΠΏΡ€Π°Π²ΡƒΡŽ Π½Π΅ ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚, Ρ‚ΠΎ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π±Π΅Π· Π΅Π΄Ρ‹.
        PutFork(Right(i));

        Think(i);

        if (token.IsCancellationRequested)
            break;
    }
}

// Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΠΆΠ΄Π°Ρ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ΅ врСмя.
bool TakeFork(int fork, int philosopher, TimeSpan? waitTime = null)
{
    return SpinWait.SpinUntil(
        () => Interlocked.CompareExchange(ref forks[fork], philosopher, 0) == 0,
              waitTime ?? TimeSpan.FromMilliseconds(-1)
    );
}

Π’Π°ΠΆΠ½ΠΎΡ‚ΠΎ Π·Π° Ρ‚ΠΎΠ·ΠΈ ΠΊΠΎΠ΄ Π΅, Ρ‡Π΅ Π΄Π²Π°ΠΌΠ° ΠΎΡ‚ Ρ‡Π΅Ρ‚ΠΈΡ€ΠΈΠΌΠ° философи забравят Π΄Π° оставят лявата си Π²ΠΈΠ»ΠΈΡ†Π°. И сС ΠΎΠΊΠ°Π·Π²Π°, Ρ‡Π΅ Ρ‚Π΅ ядат ΠΏΠΎΠ²Π΅Ρ‡Π΅ Ρ…Ρ€Π°Π½Π°, Π° Π΄Ρ€ΡƒΠ³ΠΈ Π·Π°ΠΏΠΎΡ‡Π²Π°Ρ‚ Π΄Π° Π³Π»Π°Π΄ΡƒΠ²Π°Ρ‚, Π²ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‡Π΅ Π½ΠΈΡˆΠΊΠΈΡ‚Π΅ ΠΈΠΌΠ°Ρ‚ ΡΡŠΡ‰ΠΈΡ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚. Π’ΡƒΠΊ Π½Π΅ Π³Π»Π°Π΄ΡƒΠ²Π°Ρ‚ съвсСм, Π·Π°Ρ‰ΠΎΡ‚ΠΎ... Π»ΠΎΡˆΠΈΡ‚Π΅ философи понякога Π²Ρ€ΡŠΡ‰Π°Ρ‚ Π²ΠΈΠ»ΠΈΡ†ΠΈΡ‚Π΅ си Π½Π°Π·Π°Π΄. Оказва сС, Ρ‡Π΅ Π΄ΠΎΠ±Ρ€ΠΈΡ‚Π΅ ядат ΠΎΠΊΠΎΠ»ΠΎ 5 ΠΏΡŠΡ‚ΠΈ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΠΎΡ‚ Π»ΠΎΡˆΠΈΡ‚Π΅. Π’Π°ΠΊΠ° Ρ‡Π΅ ΠΌΠ°Π»ΠΊΠ° Π³Ρ€Π΅ΡˆΠΊΠ° Π² ΠΊΠΎΠ΄Π° Π²ΠΎΠ΄ΠΈ Π΄ΠΎ спад Π² производитСлността. Π’ΡƒΠΊ ΡΡŠΡ‰ΠΎ си струва Π΄Π° сС ΠΎΡ‚Π±Π΅Π»Π΅ΠΆΠΈ, Ρ‡Π΅ Π΅ възмоТна рядка ситуация, ΠΊΠΎΠ³Π°Ρ‚ΠΎ всички философи Π²Π·Π΅ΠΌΠ°Ρ‚ лявата Π²ΠΈΠ»ΠΈΡ†Π°, няма дясна, оставят лявата, Ρ‡Π°ΠΊΠ°Ρ‚, Π²Π·Π΅ΠΌΠ°Ρ‚ ΠΎΡ‚Π½ΠΎΠ²ΠΎ лявата ΠΈ Ρ‚.Π½. Π’Π°Π·ΠΈ ситуация ΡΡŠΡ‰ΠΎ Π΅ Π³Π»Π°Π΄ΡƒΠ²Π°Π½Π΅, ΠΏΠΎ-скоро Π²Π·Π°ΠΈΠΌΠ½ΠΎ Π±Π»ΠΎΠΊΠΈΡ€Π°Π½Π΅. НС ΠΌΠΎΠΆΠ°Ρ… Π΄Π° Π³ΠΎ повторя. По-Π΄ΠΎΠ»Ρƒ Π΅ Π΄Π°Π΄Π΅Π½Π° снимка Π·Π° ситуация, Π² която Π΄Π²Π°ΠΌΠ° лоши философи са Ρ…Π²Π°Π½Π°Π»ΠΈ ΠΈ Π΄Π²Π΅Ρ‚Π΅ Π²ΠΈΠ»ΠΈΡ†ΠΈ, Π° Π΄Π²Π°ΠΌΠ° Π΄ΠΎΠ±Ρ€ΠΈ Π³Π»Π°Π΄ΡƒΠ²Π°Ρ‚.

Π”ΠΎΠ±Ρ€Π΅ ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈ философи ΠΈΠ»ΠΈ ΡΡŠΡΡ‚Π΅Π·Π°Ρ‚Π΅Π»Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅ Π² .NET

Π’ΡƒΠΊ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡ‚Π΅, Ρ‡Π΅ Π½ΠΈΡˆΠΊΠΈΡ‚Π΅ понякога сС ΡΡŠΠ±ΡƒΠΆΠ΄Π°Ρ‚ ΠΈ сС ΠΎΠΏΠΈΡ‚Π²Π°Ρ‚ Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ рСсурс. Π”Π²Π΅ ΠΎΡ‚ Ρ‡Π΅Ρ‚ΠΈΡ€ΠΈ ядра Π½Π΅ правят Π½ΠΈΡ‰ΠΎ (Π·Π΅Π»Π΅Π½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ° ΠΏΠΎ-Π³ΠΎΡ€Π΅).

Π‘ΠΌΡŠΡ€Ρ‚Ρ‚Π° Π½Π° Π΅Π΄ΠΈΠ½ философ

Π•, ΠΎΡ‰Π΅ Π΅Π΄ΠΈΠ½ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΊΠΎΠΉΡ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΡ€Π΅ΠΊΡŠΡΠ½Π΅ славната вСчСря Π½Π° философитС, Π΅ Π°ΠΊΠΎ някой ΠΎΡ‚ тях Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎ ΡƒΠΌΡ€Π΅ с Π²ΠΈΠ»ΠΈΡ†ΠΈ Π² Ρ€ΡŠΡ†Π΅ (ΠΈ Ρ‚ΠΎΠΉ Ρ‰Π΅ бъдС ΠΏΠΎΠ³Ρ€Π΅Π±Π°Π½ Ρ‚Π°ΠΊΠ°). Π’ΠΎΠ³Π°Π²Π° ΡΡŠΡΠ΅Π΄ΠΈΡ‚Π΅ Ρ‰Π΅ останат Π±Π΅Π· обяд. ΠœΠΎΠΆΠ΅Ρ‚Π΅ сами Π΄Π° измислитС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅Π½ ΠΊΠΎΠ΄ Π·Π° Ρ‚ΠΎΠ·ΠΈ случай, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚ΠΎΠΉ сС ΠΈΠ·Ρ…Π²ΡŠΡ€Π»Ρ NullReferenceException слСд ΠΊΠ°Ρ‚ΠΎ Ρ„ΠΈΠ»ΠΎΡΠΎΡ„ΡŠΡ‚ Π²Π·Π΅ΠΌΠ΅ Π²ΠΈΠ»ΠΈΡ†ΠΈΡ‚Π΅. И, ΠΌΠ΅ΠΆΠ΄Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΡ‚ΠΎ, ΠΈΠ·ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅Ρ‚ΠΎ няма Π΄Π° бъдС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π΅Π½ΠΎ ΠΈ извикващият ΠΊΠΎΠ΄ няма просто Π΄Π° Π³ΠΎ ΡƒΠ»ΠΎΠ²ΠΈ (Π·Π° Ρ‚ΠΎΠ²Π° AppDomain.CurrentDomain.UnhandledException ΠΈ Ρ‚.Π½.). Π‘Π»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»Π½ΠΎ са Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈ ΠΌΠ°Π½ΠΈΠΏΡƒΠ»Π°Ρ‚ΠΎΡ€ΠΈ Π½Π° Π³Ρ€Π΅ΡˆΠΊΠΈ Π² самитС нишки ΠΈ с Π΅Π»Π΅Π³Π°Π½Ρ‚Π½ΠΎ прСкратяванС.

ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€

Π”ΠΎΠ±Ρ€Π΅, ΠΊΠ°ΠΊ Π΄Π° Ρ€Π΅ΡˆΠΈΠΌ Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с Π±Π΅Π·ΠΈΠ·Ρ…ΠΎΠ΄ΠΈΡ†Π°Ρ‚Π°, Π³Π»Π°Π΄Π° ΠΈ ΡΠΌΡŠΡ€Ρ‚Π½ΠΈΡ‚Π΅ случаи? Π©Π΅ допуснСм само Π΅Π΄ΠΈΠ½ философ Π΄ΠΎ разклонСнията ΠΈ Ρ‰Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π²Π·Π°ΠΈΠΌΠ½ΠΎ ΠΈΠ·ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅ Π½Π° нишки Π·Π° Ρ‚ΠΎΠ²Π° място. Как Π΄Π° Π³ΠΎ Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ? Π”Π° ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Π΅ Π΄ΠΎ философитС ΠΈΠΌΠ° ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€, ΠΊΠΎΠΉΡ‚ΠΎ Π΄Π°Π²Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π½Π° Π΅Π΄ΠΈΠ½ философ Π΄Π° Π²Π·Π΅ΠΌΠ΅ Π²ΠΈΠ»ΠΈΡ†ΠΈΡ‚Π΅. Как трябва Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ Ρ‚ΠΎΠ·ΠΈ ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€ ΠΈ ΠΊΠ°ΠΊ Ρ‰Π΅ Π³ΠΎ Π·Π°Π΄Π°Π΄Π°Ρ‚ философитС са интСрСсни Π²ΡŠΠΏΡ€ΠΎΡΠΈ.

Най-простият Π½Π°Ρ‡ΠΈΠ½ Π΅ философитС просто постоянно Π΄Π° молят ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€Π° Π·Π° Π΄ΠΎΡΡ‚ΡŠΠΏ Π΄ΠΎ Π²ΠΈΠ»ΠΈΡ†ΠΈΡ‚Π΅. Π’Π΅Π·ΠΈ. Π‘Π΅Π³Π° философитС няма Π΄Π° Ρ‡Π°ΠΊΠ°Ρ‚ Π²ΠΈΠ»ΠΈΡ†Π° Π½Π°Π±Π»ΠΈΠ·ΠΎ, Π° Ρ‡Π°ΠΊΠ°Ρ‚ ΠΈΠ»ΠΈ ΠΏΠΈΡ‚Π°Ρ‚ ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€Π°. ΠŸΡŠΡ€Π²ΠΎΠ½Π°Ρ‡Π°Π»Π½ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ само потрСбитСлско пространство Π·Π° Ρ‚ΠΎΠ²Π°; Π² Π½Π΅Π³ΠΎ Π½Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΏΡ€Π΅ΠΊΡŠΡΠ²Π°Π½ΠΈΡ Π·Π° ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ Π½Π° ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€ΠΈ ΠΎΡ‚ ядрото (ΠΏΠΎΠ²Π΅Ρ‡Π΅ Π·Π° тях ΠΏΠΎ-Π΄ΠΎΠ»Ρƒ).

РСшСния Π·Π° потрСбитСлско пространство

Π’ΡƒΠΊ Ρ‰Π΅ Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ ΡΡŠΡ‰ΠΎΡ‚ΠΎ, ΠΊΠΎΠ΅Ρ‚ΠΎ Π½Π°ΠΏΡ€Π°Π²ΠΈΡ…ΠΌΠ΅ ΠΏΡ€Π΅Π΄ΠΈ с Π΅Π΄Π½Π° Π²ΠΈΠ»ΠΈΡ†Π° ΠΈ Π΄Π²Π° философа, Ρ‰Π΅ сС Π²ΡŠΡ€Ρ‚ΠΈΠΌ Π² Ρ†ΠΈΠΊΡŠΠ» ΠΈ Ρ‰Π΅ Ρ‡Π°ΠΊΠ°ΠΌΠ΅. Но сСга Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ всички философи ΠΈ, Ρ‚Π°ΠΊΠ° Π΄Π° сС ΠΊΠ°ΠΆΠ΅, само Π΅Π΄Π½Π° Π²ΠΈΠ»ΠΈΡ†Π°, Ρ‚.Π΅. ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΊΠ°ΠΆΠ΅ΠΌ, Ρ‡Π΅ само Ρ„ΠΈΠ»ΠΎΡΠΎΡ„ΡŠΡ‚, ΠΊΠΎΠΉΡ‚ΠΎ Π΅ Π²Π·Π΅Π» Ρ‚Π°Π·ΠΈ β€žΠ·Π»Π°Ρ‚Π½Π° Π²ΠΈΠ»ΠΈΡ†Π°β€œ ΠΎΡ‚ ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€Π°, Ρ‰Π΅ ядС. Π—Π° Ρ†Π΅Π»Ρ‚Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ SpinLock.

private static SpinLock spinLock = new SpinLock();  // Наш "ΠΎΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚"
private void RunSpinLock(int i, CancellationToken token)
{
    while (true)
    {
        // Взаимная Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ° Ρ‡Π΅Ρ€Π΅Π· busy waiting. Π’Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Π΄ΠΎ try, Ρ‡Ρ‚ΠΎΠ±Ρ‹
        // Π²Ρ‹Π±Ρ€Π°ΡΠΈΡ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π² случаС ошибки Π² самом SpinLock.
        bool hasLock = false;
        spinLock.Enter(ref hasLock);
        try
        {
            // Π—Π΄Π΅ΡΡŒ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ ΠΏΠΎΡ‚ΠΎΠΊ (mutual exclusion).
            forks[Left(i)] = i + 1;  // Π‘Π΅Ρ€Π΅ΠΌ Π²ΠΈΠ»ΠΊΡƒ сразу, Π±Π΅Π· оТидания.
            forks[Right(i)] = i + 1;
            eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
            forks[Left(i)] = 0;
            forks[Right(i)] = 0;
        }
        finally
        {
            if(hasLock) spinLock.Exit();  // ИзбСгаСм ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ со ΡΠΌΠ΅Ρ€Ρ‚ΡŒΡŽ философа.
        }

        Think(i);

        if (token.IsCancellationRequested)
            break;
    }
}

SpinLock Ρ‚ΠΎΠ²Π° Π΅ Π±Π»ΠΎΠΊΠ΅Ρ€, с, Π³Ρ€ΡƒΠ±ΠΎ ΠΊΠ°Π·Π°Π½ΠΎ, ΡΡŠΡ‰ΠΎΡ‚ΠΎ while(true) { if (!lock) break; }, Π½ΠΎ с ΠΎΡ‰Π΅ ΠΏΠΎΠ²Π΅Ρ‡Π΅ β€žΠΌΠ°Π³ΠΈΡβ€œ, ΠΎΡ‚ΠΊΠΎΠ»ΠΊΠΎΡ‚ΠΎ Π² SpinWait (ΠΊΠΎΠ΅Ρ‚ΠΎ сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Ρ‚Π°ΠΌ). Π‘Π΅Π³Π° Ρ‚ΠΎΠΉ Π·Π½Π°Π΅ ΠΊΠ°ΠΊ Π΄Π° Π±Ρ€ΠΎΠΈ Ρ‡Π°ΠΊΠ°Ρ‰ΠΈΡ‚Π΅, Π΄Π° Π³ΠΈ приспи ΠΌΠ°Π»ΠΊΠΎ ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ²Π΅Ρ‡Π΅. ΠΈ Ρ‚.Π½. ΠšΠ°Ρ‚ΠΎ цяло ΠΏΡ€Π°Π²ΠΈ всичко възмоТно Π΄Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€Π°. Но трябва Π΄Π° ΠΏΠΎΠΌΠ½ΠΈΠΌ, Ρ‡Π΅ Ρ‚ΠΎΠ²Π° всС ΠΎΡ‰Π΅ Π΅ ΡΡŠΡ‰ΠΈΡΡ‚ Π°ΠΊΡ‚ΠΈΠ²Π΅Π½ Ρ†ΠΈΠΊΡŠΠ», ΠΊΠΎΠΉΡ‚ΠΎ изяТда рСсурситС Π½Π° процСсора ΠΈ ΠΏΠΎΠ΄Π΄ΡŠΡ€ΠΆΠ° нишка, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° Π΄ΠΎΠ²Π΅Π΄Π΅ Π΄ΠΎ Π³Π»Π°Π΄, Π°ΠΊΠΎ Π΅Π΄ΠΈΠ½ ΠΎΡ‚ философитС станС с ΠΏΠΎ-голям ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ ΠΎΡ‚ останалитС, Π½ΠΎ няма Π·Π»Π°Ρ‚Π½Π° Π²ΠΈΠ»ΠΊΠ° (ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с инвСрсията Π½Π° ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π° ). Π—Π°Ρ‚ΠΎΠ²Π° Π³ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ само Π·Π° ΠΌΠ½ΠΎΠ³ΠΎ ΠΌΠ½ΠΎΠ³ΠΎ ΠΊΡ€Π°Ρ‚ΠΊΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Π² сподСлСната ΠΏΠ°ΠΌΠ΅Ρ‚, Π±Π΅Π· Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈ извиквания Π½Π° Ρ‚Ρ€Π΅Ρ‚ΠΈ страни, Π²Π»ΠΎΠΆΠ΅Π½ΠΈ Π·Π°ΠΊΠ»ΡŽΡ‡Π²Π°Π½ΠΈΡ ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ ΠΈΠ·Π½Π΅Π½Π°Π΄ΠΈ.

Π”ΠΎΠ±Ρ€Π΅ ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈ философи ΠΈΠ»ΠΈ ΡΡŠΡΡ‚Π΅Π·Π°Ρ‚Π΅Π»Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅ Π² .NET

РисуванС Π·Π° SpinLock. ΠŸΠΎΡ‚ΠΎΡ†ΠΈΡ‚Π΅ Π½Π΅ΠΏΡ€Π΅ΠΊΡŠΡΠ½Π°Ρ‚ΠΎ сС β€žΠ±ΠΎΡ€ΡΡ‚β€œ Π·Π° Π·Π»Π°Ρ‚Π½Π°Ρ‚Π° Π²ΠΈΠ»ΠΊΠ°. Π’ΡŠΠ·Π½ΠΈΠΊΠ²Π°Ρ‚ ΠΏΠΎΠ²Ρ€Π΅Π΄ΠΈ - ΠΌΠ°Ρ€ΠΊΠΈΡ€Π°Π½Π°Ρ‚Π° област Π½Π° Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ‚Π°. Π―Π΄Ρ€Π°Ρ‚Π° Π½Π΅ сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚ напълно: само ΠΎΠΊΠΎΠ»ΠΎ 2/3 ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ Ρ‡Π΅Ρ‚ΠΈΡ€ΠΈ нишки.

Π”Ρ€ΡƒΠ³ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Ρ‚ΡƒΠΊ Π±ΠΈ Π±ΠΈΠ»ΠΎ Π΄Π° сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° само Interlocked.CompareExchange със ΡΡŠΡ‰ΠΎΡ‚ΠΎ Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΠΈΠ·Ρ‡Π°ΠΊΠ²Π°Π½Π΅, ΠΊΠ°ΠΊΡ‚ΠΎ Π΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π² ΠΊΠΎΠ΄Π° ΠΏΠΎ-Π³ΠΎΡ€Π΅ (ΠΏΡ€ΠΈ Π³Π»Π°Π΄ΡƒΠ²Π°Ρ‰ΠΈ философи), Π½ΠΎ Ρ‚ΠΎΠ²Π°, ΠΊΠ°ΠΊΡ‚ΠΎ Π²Π΅Ρ‡Π΅ бСшС ΠΊΠ°Π·Π°Π½ΠΎ, Ρ‚Π΅ΠΎΡ€Π΅Ρ‚ΠΈΡ‡Π½ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° Π΄ΠΎΠ²Π΅Π΄Π΅ Π΄ΠΎ Π±Π»ΠΎΠΊΠΈΡ€Π°Π½Π΅.

Около Interlocked струва си Π΄Π° сС ΠΊΠ°ΠΆΠ΅, Ρ‡Π΅ ΠΈΠΌΠ° Π½Π΅ само CompareExchange, Π½ΠΎ ΡΡŠΡ‰ΠΎ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΈ Π·Π° Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎ Ρ‡Π΅Ρ‚Π΅Π½Π΅ И писанС. И Ρ‡Ρ€Π΅Π· повтарянС Π½Π° промяната, Π°ΠΊΠΎ Π΄Ρ€ΡƒΠ³Π° нишка успСС Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈ своитС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ (Ρ‡Π΅Ρ‚Π΅Π½Π΅ 1, Ρ‡Π΅Ρ‚Π΅Π½Π΅ 2, запис 2, запис 1 Π΅ лошо), тя ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π·Π° слоТни ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Π½Π° Π΅Π΄Π½Π° стойност (ΠΌΠΎΠ΄Π΅Π» Π·Π° Π±Π»ΠΎΠΊΠΈΡ€Π°Π½Π΅ Π½Π° всичко).

РСшСния Π·Π° Ρ€Π΅ΠΆΠΈΠΌ Π½Π° ядрото

Π—Π° Π΄Π° ΠΈΠ·Π±Π΅Π³Π½Π΅ΠΌ Π·Π°Π³ΡƒΠ±Π°Ρ‚Π° Π½Π° рСсурси Π² Ρ†ΠΈΠΊΡŠΠ», Π½Π΅ΠΊΠ° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΊΠ°ΠΊ Π΄Π° Π±Π»ΠΎΠΊΠΈΡ€Π°ΠΌΠ΅ нишка. Π‘ Π΄Ρ€ΡƒΠ³ΠΈ Π΄ΡƒΠΌΠΈ, ΠΏΡ€ΠΎΠ΄ΡŠΠ»ΠΆΠ°Π²Π°ΠΉΠΊΠΈ нашия ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π½Π΅ΠΊΠ° Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠ°ΠΊ ΡΠ΅Ρ€Π²ΠΈΡ‚ΡŒΠΎΡ€ΡŠΡ‚ приспива философа ΠΈ Π³ΠΎ ΡΡŠΠ±ΡƒΠΆΠ΄Π° само ΠΊΠΎΠ³Π°Ρ‚ΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ. ΠŸΡŠΡ€Π²ΠΎ, Π½Π΅ΠΊΠ° Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΊΠ°ΠΊ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ Ρ‚ΠΎΠ²Π° Ρ‡Ρ€Π΅Π· Ρ€Π΅ΠΆΠΈΠΌΠ° Π½Π° ядрото Π½Π° ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Π°Ρ‚Π° систСма. Всички структури Ρ‚Π°ΠΌ чСсто сС ΠΎΠΊΠ°Π·Π²Π°Ρ‚ ΠΏΠΎ-Π±Π°Π²Π½ΠΈ ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ Π² потрСбитСлското пространство. Няколко ΠΏΡŠΡ‚ΠΈ ΠΏΠΎ-Π±Π°Π²Π½ΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ AutoResetEvent ΠΌΠΎΠΆΠ΅ Π±ΠΈ 53 ΠΏΡŠΡ‚ΠΈ ΠΏΠΎ-Π±Π°Π²Π½ΠΎ SpinLock [Π ΠΈΡ…Ρ‚Π΅Ρ€]. Но с тяхна ΠΏΠΎΠΌΠΎΡ‰ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° синхронизиратС процСситС Π² цялата систСма, управлявани ΠΈΠ»ΠΈ Π½Π΅.

ΠžΡΠ½ΠΎΠ²Π½ΠΈΡΡ‚ Π΄ΠΈΠ·Π°ΠΉΠ½ Ρ‚ΡƒΠΊ Π΅ сСмафор, ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ ΠΎΡ‚ ДСйкстра ΠΏΡ€Π΅Π΄ΠΈ ΠΏΠΎΠ²Π΅Ρ‡Π΅ ΠΎΡ‚ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½ Π²Π΅ΠΊ. Π‘Π΅ΠΌΠ°Ρ„ΠΎΡ€ΡŠΡ‚ Π΅, Π½Π°ΠΉ-просто ΠΊΠ°Π·Π°Π½ΠΎ, ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚Π΅Π»Π½ΠΎ цяло число, управлявано ΠΎΡ‚ систСмата, ΠΈ Π΄Π²Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π²ΡŠΡ€Ρ…Ρƒ Π½Π΅Π³ΠΎ - ΡƒΠ²Π΅Π»ΠΈΡ‡Π°Π²Π°Π½Π΅ ΠΈ намаляванС. Ако Π½Π΅ Π΅ възмоТно Π΄Π° сС Π½Π°ΠΌΠ°Π»ΠΈ Π½ΡƒΠ»Π°Ρ‚Π°, Ρ‚ΠΎΠ³Π°Π²Π° ΠΈΠ·Π²ΠΈΠΊΠ²Π°Ρ‰Π°Ρ‚Π° нишка сС Π±Π»ΠΎΠΊΠΈΡ€Π°. ΠšΠΎΠ³Π°Ρ‚ΠΎ броят сС ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³Π° Π°ΠΊΡ‚ΠΈΠ²Π½Π° нишка/процСс, Ρ‚ΠΎΠ³Π°Π²Π° Π½ΠΈΡˆΠΊΠΈΡ‚Π΅ сС ΠΏΡ€Π΅Π΄Π°Π²Π°Ρ‚ ΠΈ ΡΠ΅ΠΌΠ°Ρ„ΠΎΡ€ΡŠΡ‚ ΠΎΡ‚Π½ΠΎΠ²ΠΎ сС намалява с прСдадСния Π±Ρ€ΠΎΠΉ. ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° си прСдставитС Π²Π»Π°ΠΊΠΎΠ²Π΅ Π² тясно място със сСмафор. .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), Ρ‚ΠΎΠ³Π°Π²Π° философитС Ρ‰Π΅ Ρ‡Π°ΠΊΠ°Ρ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΡ†ΠΈΡ‚Π΅, Π·Π°Ρ‰ΠΎΡ‚ΠΎ НамиранСто Π½Π° Π³Ρ€Π΅ΡˆΠΊΠΈ Π² Ρ‚Π°ΠΊΡŠΠ² ΠΊΠΎΠ΄ Π΅ доста Ρ‚Ρ€ΡƒΠ΄Π½Π° Π·Π°Π΄Π°Ρ‡Π°. Π”Ρ€ΡƒΠ³ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с Ρ‚ΠΎΠ²Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π΅, Ρ‡Π΅ Ρ‚ΠΎ Π½Π΅ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€Π°, Ρ‡Π΅ някой философ няма Π΄Π° ΡƒΠΌΡ€Π΅ ΠΎΡ‚ Π³Π»Π°Π΄.

Π₯ΠΈΠ±Ρ€ΠΈΠ΄Π½ΠΈ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ

Π Π°Π·Π³Π»Π΅Π΄Π°Ρ…ΠΌΠ΅ Π΄Π²Π° ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° Π·Π° синхронизация, ΠΊΠΎΠ³Π°Ρ‚ΠΎ оставамС Π² потрСбитСлски Ρ€Π΅ΠΆΠΈΠΌ ΠΈ сС Π²ΡŠΡ€Ρ‚ΠΈΠΌ Π² Ρ†ΠΈΠΊΡŠΠ» ΠΈ ΠΊΠΎΠ³Π°Ρ‚ΠΎ Π±Π»ΠΎΠΊΠΈΡ€Π°ΠΌΠ΅ Π½ΠΈΡˆΠΊΠ°Ρ‚Π° ΠΏΡ€Π΅Π· ядрото. ΠŸΡŠΡ€Π²ΠΈΡΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π΅ Π΄ΠΎΠ±ΡŠΡ€ Π·Π° къси Π±Π»ΠΎΠΊΠΎΠ²Π΅, вторият Π·Π° дълги. ЧСсто трябва ΠΏΡŠΡ€Π²ΠΎ Π΄Π° ΠΈΠ·Ρ‡Π°ΠΊΠ°Ρ‚Π΅ Π·Π° ΠΊΡ€Π°Ρ‚ΠΊΠΎ Π΄Π°Π΄Π΅Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° Π΄Π° сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Π² Ρ†ΠΈΠΊΡŠΠ» ΠΈ слСд Ρ‚ΠΎΠ²Π° Π΄Π° Π±Π»ΠΎΠΊΠΈΡ€Π°Ρ‚Π΅ Π½ΠΈΡˆΠΊΠ°Ρ‚Π°, ΠΊΠΎΠ³Π°Ρ‚ΠΎ Ρ‡Π°ΠΊΠ°Π½Π΅Ρ‚ΠΎ Π΅ дълго. Π’ΠΎΠ·ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΠΈΡ€Π°Π½ Π² Ρ‚.Π½Π°Ρ€. Ρ…ΠΈΠ±Ρ€ΠΈΠ΄Π½ΠΈ Π΄ΠΈΠ·Π°ΠΉΠ½ΠΈ. Π’ΠΎΠΉ ΠΈΠΌΠ° ΡΡŠΡ‰ΠΈΡ‚Π΅ конструкции ΠΊΠ°Ρ‚ΠΎ Π·Π° Ρ€Π΅ΠΆΠΈΠΌ Π½Π° ядрото, Π½ΠΎ сСга с Ρ†ΠΈΠΊΡŠΠ» Π½Π° потрСбитСлски Ρ€Π΅ΠΆΠΈΠΌ: 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), ΠΊΠΎΠΈΡ‚ΠΎ ΠΏΡ€ΠΈΡΡŠΡΡ‚Π²Π°Ρ‚ във всички ΠΎΠ±Π΅ΠΊΡ‚ΠΈ. Π‘Π»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»Π½ΠΎ, Π°ΠΊΠΎ Π΅ ΠΈΠ·Π±Ρ€Π°Π½ нСподходящ ΠΎΠ±Π΅ΠΊΡ‚, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ лСсно Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Π±Π»ΠΎΠΊΠΈΡ€Π°Π½Π΅ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π°ΠΊΠΎ Π·Π°ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ ΠΈΠ½Ρ‚Π΅Ρ€Π½ΠΈΡ€Π°Π½ Π½ΠΈΠ·). Π’ΠΈΠ½Π°Π³ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ скрит ΠΏΡ€Π΅Π΄ΠΌΠ΅Ρ‚ Π·Π° Ρ‚ΠΎΠ²Π°.

ΠœΠΎΠ΄Π΅Π»ΡŠΡ‚ Condition Variable Π²ΠΈ позволява ΠΏΠΎ-сбито Π΄Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠΈΡ‚Π΅ ΠΎΡ‡Π°ΠΊΠ²Π°Π½Π΅Ρ‚ΠΎ Π½Π° някакво слоТно условиС. Π’ .NET Π΅ нСпълно спорСд ΠΌΠ΅Π½, Π·Π°Ρ‰ΠΎΡ‚ΠΎ... На тСория трябва Π΄Π° ΠΈΠΌΠ° няколко опашки Π·Π° няколко ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ (ΠΊΠ°ΠΊΡ‚ΠΎ Π² Posix Threads), Π° Π½Π΅ Π·Π° Π΅Π΄Π½ΠΎ Π·Π°ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅. Π’ΠΎΠ³Π°Π²Π° Π±ΠΈ Π±ΠΈΠ»ΠΎ възмоТно Π΄Π° Π³ΠΈ Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ Π·Π° всички философи. Но Π΄ΠΎΡ€ΠΈ ΠΈ Π² Ρ‚Π°Π·ΠΈ Ρ„ΠΎΡ€ΠΌΠ° Π²ΠΈ позволява Π΄Π° ΡΡŠΠΊΡ€Π°Ρ‚ΠΈΡ‚Π΅ ΠΊΠΎΠ΄Π°.

Много философи ΠΈΠ»ΠΈ async / await

Π”ΠΎΠ±Ρ€Π΅, сСга ΠΌΠΎΠΆΠ΅ΠΌ Π΅Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ Π΄Π° Π±Π»ΠΎΠΊΠΈΡ€Π°ΠΌΠ΅ Ρ‚Π΅ΠΌΠΈ. Но ΠΊΠ°ΠΊΠ²ΠΎ Ρ‰Π΅ станС, Π°ΠΊΠΎ ΠΈΠΌΠ°ΠΌΠ΅ ΠΌΠ½ΠΎΠ³ΠΎ философи? 100? 10000 100000? НапримСр, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ…ΠΌΠ΅ 4 XNUMX заявки към ΡƒΠ΅Π± ΡΡŠΡ€Π²ΡŠΡ€Π°. Π‘ΡŠΠ·Π΄Π°Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° нишка Π·Π° всяка заявка Ρ‰Π΅ бъдС скъпо, Π·Π°Ρ‰ΠΎΡ‚ΠΎ Ρ‚ΠΎΠ»ΠΊΠΎΠ²Π° ΠΌΠ½ΠΎΠ³ΠΎ нишки няма Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ изпълнСни ΠΏΠ°Ρ€Π°Π»Π΅Π»Π½ΠΎ. Π‘Π°ΠΌΠΎ Ρ‚ΠΎΠ»ΠΊΠΎΠ²Π° логичСски ядра Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ изпълнСни (ΠΈΠΌΠ°ΠΌ XNUMX). А всички останали просто Ρ‰Π΅ ΠΎΡ‚Π½Π΅ΠΌΠ°Ρ‚ рСсурси. Π•Π΄Π½ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π½Π° Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Π΅ ΠΌΠΎΠ΄Π΅Π»ΡŠΡ‚ 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 нишки ΠΈ ΠΈΠ·ΠΎΠ±Ρ‰ΠΎ Π½Π΅ изпълни останалитС. Всяка ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ 4 нишки бСшС Π½Π΅Π°ΠΊΡ‚ΠΈΠ²Π½Π° Π·Π° ΠΎΠΊΠΎΠ»ΠΎ 2ms. А Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ async/await изпълни всичкитС 100, със срСдно 6.8 сСкунди всяко ΠΈΠ·Ρ‡Π°ΠΊΠ²Π°Π½Π΅. Π Π°Π·Π±ΠΈΡ€Π° сС, Π² Ρ€Π΅Π°Π»Π½ΠΈ систСми бСздСйствиСто Π·Π° 6 сСкунди Π΅ нСдопустимо ΠΈ Π΅ ΠΏΠΎ-Π΄ΠΎΠ±Ρ€Π΅ Π΄Π° Π½Π΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π²Π°Ρ‚Π΅ Ρ‚ΠΎΠ»ΠΊΠΎΠ²Π° ΠΌΠ½ΠΎΠ³ΠΎ заявки ΠΏΠΎ Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½. Π Π΅ΡˆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ с ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ сС ΠΎΠΊΠ°Π·Π° Π½ΠΈΠΊΠ°ΠΊ Π½Π΅ ΠΌΠ°Ρ‰Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎ.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

ΠšΠ°ΠΊΡ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡ‚Π΅ ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ ΠΌΠ°Π»ΠΊΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΈ, .NET ΠΏΠΎΠ΄Π΄ΡŠΡ€ΠΆΠ° ΠΌΠ½ΠΎΠ³ΠΎ конструкции Π·Π° синхронизация. Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‚ΠΎΠ²Π°, Π½Π΅ Π²ΠΈΠ½Π°Π³ΠΈ Π΅ ΠΎΡ‡Π΅Π²ΠΈΠ΄Π½ΠΎ ΠΊΠ°ΠΊ Π΄Π° Π³ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅. Надявам сС Ρ‚Π°Π·ΠΈ статия Π΄Π° Π΅ Π±ΠΈΠ»Π° ΠΏΠΎΠ»Π΅Π·Π½Π°. Π—Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° ΠΏΡ€ΠΈΠΊΠ»ΡŽΡ‡Π²Π°ΠΌΠ΅, Π½ΠΎ всС ΠΎΡ‰Π΅ ΠΈΠΌΠ° ΠΌΠ½ΠΎΠ³ΠΎ интСрСсни Π½Π΅Ρ‰Π°, ΠΊΠ°Ρ‚ΠΎ ΠΊΠΎΠ»Π΅ΠΊΡ†ΠΈΠΈ, бСзопасни Π·Π° нишки, TPL ΠΏΠΎΡ‚ΠΎΠΊ ΠΎΡ‚ Π΄Π°Π½Π½ΠΈ, Ρ€Π΅Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅, ΠΌΠΎΠ΄Π΅Π» Π½Π° софтуСрни Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ ΠΈ Ρ‚.Π½.

ΠΈΠ·Ρ‚ΠΎΡ‡Π½ΠΈΡ†ΠΈ

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€