Π‘Ρ‹Ρ‚Ρ‹Π΅ философы ΠΈΠ»ΠΈ ΠΊΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° .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 создаСт ΠΈΠ»ΠΈ удаляСт ΠΏΠΎΡ‚ΠΎΠΊΠΈ Π² зависимости ΠΎΡ‚ количСства этих Π·Π°Π΄Π°Ρ‡. Один ΠΏΡƒΠ» Π½Π° всС AppDomain’Ρ‹. Π­Ρ‚ΠΎΡ‚ ΠΏΡƒΠ» стоит ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΡ‡Ρ‚ΠΈ всСгда, Ρ‚.ΠΊ. Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΌΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Ρ‚ΡŒΡΡ с созданиСм, ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ², ΠΈΡ… очСрСдями ΠΈ ΠΏΡ€. МоТно ΠΈ Π±Π΅Π· ΠΏΡƒΠ»Π°, Π½ΠΎ Ρ‚ΠΎΠ³Π΄Π° придСтся Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Thread, это цСлСсообразно для случаСв, ΠΊΠΎΠ³Π΄Π° Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ ΠΏΠΎΡ‚ΠΎΠΊΡƒ, ΠΊΠΎΠ³Π΄Π° Ρƒ нас долгая опСрация, для Foreground ΠΏΠΎΡ‚ΠΎΠΊΠ° ΠΈ Π΄Ρ€.

Π”Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, System.Threading.Tasks.Task класс β€” это Ρ‚ΠΎΡ‚ ΠΆΠ΅ Thread, Π½ΠΎ со всякими удобствами: Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ таск послС Π±Π»ΠΎΠΊΠ° Π΄Ρ€ΡƒΠ³ΠΈΡ… тасков, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ ΠΈΡ… ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΡƒΠ΄ΠΎΠ±Π½ΠΎ ΠΈΡ… ΠΏΡ€Π΅Ρ€Ρ‹Π²Π°Ρ‚ΡŒ ΠΈ ΠΌΠ½. Π΄Ρ€. Они Π½ΡƒΠΆΠ½Ρ‹ для ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ async/await конструкций (Task-based Asynchronous Pattern, синтаксичСский сахар для оТидания 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

На рисункС, Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² (deadlock). Π—Π΅Π»Π΅Π½Ρ‹ΠΌ Ρ†Π²Π΅Ρ‚ΠΎΠΌ β€” Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅, красным β€” синхронизация, сСрым β€” ΠΏΠΎΡ‚ΠΎΠΊ спит. Π ΠΎΠΌΠ±ΠΈΠΊΠ°ΠΌΠΈ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π΅Π½ΠΎ врСмя запуска Task’ΠΎΠ².

Π“ΠΎΠ»ΠΎΠ΄ философов

Π₯отя Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΌΡ‹ΡΠ»ΠΈΡ‚ΡŒ особСнно ΠΌΠ½ΠΎΠ³ΠΎ Π΅Π΄Ρ‹ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ, Π½ΠΎ Π³ΠΎΠ»ΠΎΠ΄ ΠΊΠΎΠ³ΠΎ ΡƒΠ³ΠΎΠ΄Π½ΠΎ Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ Ρ„ΠΈΠ»ΠΎΡΠΎΡ„ΠΈΡŽ. ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΡΠΌΠΎΠ΄Π΅Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ голодания ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² Π² нашСй Π·Π°Π΄Π°Ρ‡Π΅. Π“ΠΎΠ»ΠΎΠ΄Π°Π½ΠΈΠ΅ β€” это ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΡ‚ΠΎΠΊ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚, Π½ΠΎ Π±Π΅Π· сущСствСнной Ρ€Π°Π±ΠΎΡ‚Ρ‹, Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами это Ρ‚ΠΎΡ‚ ΠΆΠ΅ Π΄Π΅Π΄Π»ΠΎΠΊ, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΡ‚ΠΎΠΊ Π½Π΅ спит, Π° Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΠΈΡ‰Π΅Ρ‚ ΠΊΠ°ΠΊ Π±Ρ‹ ΠΏΠΎΠ΅ΡΡ‚ΡŒ, Π½ΠΎ Π΅Π΄Ρ‹ Π½Π΅Ρ‚. Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ Ρ‡Π°ΡΡ‚ΡƒΡŽ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΡƒ Π±ΡƒΠ΄Π΅ΠΌ ΠΊΠ»Π°ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΡƒ Π½Π°Π·Π°Π΄, Ссли Π½Π΅ смогли Π²Π·ΡΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΡƒΡŽ.

// Π’ΠΎ ΠΆΠ΅ Ρ‡Ρ‚ΠΎ ΠΈ Π² 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 ΠΈ Π΄Ρ€.). ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ошибок Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ Π² самих ΠΏΠΎΡ‚ΠΎΠΊΠ°Ρ… ΠΈ с ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½Ρ‹ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ΠΌ.

ΠžΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚

Π₯ΠΎΡ€ΠΎΡˆΠΎ, ΠΊΠ°ΠΊ Π½Π°ΠΌ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ с Π²Π·Π°ΠΈΠΌΠ½Ρ‹ΠΌΠΈ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ°ΠΌΠΈ, Π³ΠΎΠ»ΠΎΠ΄Π°Π½ΠΈΠ΅ΠΌ ΠΈ смСртями? Π‘ΡƒΠ΄Π΅ΠΌ Π΄ΠΎΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½ΠΎΠ³ΠΎ философа Π΄ΠΎ Π²ΠΈΠ»ΠΎΠΊ, Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π²Π·Π°ΠΈΠΌΠ½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ (mutual exclusion) ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² для этого мСста. Как это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ? ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ рядом с философами стоит ΠΎΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π΄Π°Π΅Ρ‚ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΊΠ°ΠΊΠΎΠΌΡƒ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ ΠΎΠ΄Π½ΠΎΠΌΡƒ философу Π²Π·ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ. Как Π½Π°ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ этого ΠΎΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚Π° ΠΈ ΠΊΠ°ΠΊ философы Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ Π΅Π³ΠΎ, вопросы интСрСсныС.

ΠŸΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠΈΠΉ способ β€” это ΠΊΠΎΠ³Π΄Π° философы Π±ΡƒΠ΄ΡƒΡ‚ просто постоянно ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚Π° Π΄Π°Ρ‚ΡŒ доступ ΠΊ Π²ΠΈΠ»ΠΊΠ°ΠΌ. Π’.Π΅. Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ философы Π±ΡƒΠ΄ΡƒΡ‚ Π½Π΅ ΠΆΠ΄Π°Ρ‚ΡŒ Π²ΠΈΠ»ΠΊΡƒ рядом, Π° ΠΆΠ΄Π°Ρ‚ΡŒ ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚Π°. Π‘Π½Π°Ρ‡Π°Π»Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ для этого Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 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 (ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ‚Π°ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ). Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΎΠ½ ΡƒΠΌΠ΅Π΅Ρ‚ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΡ…, Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΡƒΡΡ‹ΠΏΠ»ΡΡ‚ΡŒ ΠΈΡ… ΠΈ ΠΌΠ½. Π΄Ρ€. Π’ ΠΎΠ±Ρ‰Π΅ΠΌ, Π΄Π΅Π»Π°Π΅Ρ‚ всё Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ΅ для ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ. Но Π½Π°Π΄ΠΎ ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ это всё Ρ‚ΠΎΡ‚ ΠΆΠ΅ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Сст рСсурсы процСссора ΠΈ Π΄Π΅Ρ€ΠΆΠΈΡ‚ ΠΏΠΎΡ‚ΠΎΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ голоданию, Ссли ΠΎΠ΄ΠΈΠ½ ΠΈΠ· философов ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒΡΡ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π½Π΅Π΅ Π΄Ρ€ΡƒΠ³ΠΈΡ…, Π½ΠΎ Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Π²ΠΈΠ»ΠΊΠΈ (Priority Inversion problem). ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π΅Π³ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΎΡ‡Π΅Π½ΡŒ ΠΎΡ‡Π΅Π½ΡŒ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΡ… ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΠΎΠ±Ρ‰Π΅ΠΉ памяти, Π±Π΅Π· всяких сторонних Π²Ρ‹Π·ΠΎΠ²ΠΎΠ², Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΎΠΊ ΠΈ ΠΏΡ€. ΡΡŽΡ€ΠΏΡ€ΠΈΠ·ΠΎΠ².

Π‘Ρ‹Ρ‚Ρ‹Π΅ философы ΠΈΠ»ΠΈ ΠΊΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° .NET

Рисунок для SpinLock. ΠŸΠΎΡ‚ΠΎΠΊΠΈ постоянно «Π²ΠΎΡŽΡŽΡ‚» Π·Π° Π·ΠΎΠ»ΠΎΡ‚ΡƒΡŽ Π²ΠΈΠ»ΠΊΡƒ. Π‘Π»ΡƒΡ‡Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΎΠ²Π°Π»Ρ‹ β€” Π½Π° рисункС выдСлСнная ΠΎΠ±Π»Π°ΡΡ‚ΡŒ. Π―Π΄Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Π½Π΅ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ: Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠΊΠΎΠ»ΠΎ 2/3 этими Ρ‡Π΅Ρ‚Ρ‹Ρ€ΡŒΠΌΡ ΠΏΠΎΡ‚ΠΎΠΊΠ°ΠΌΠΈ.

Π”Ρ€ΡƒΠ³ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ здСсь Π±Ρ‹Π»ΠΎ Π±Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Interlocked.CompareExchange с Ρ‚Π΅ΠΌ ΠΆΠ΅ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ΠΌ, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π² ΠΊΠΎΠ΄Π΅ Π²Ρ‹ΡˆΠ΅ (Π² Π³ΠΎΠ»ΠΎΠ΄Π°ΡŽΡ‰ΠΈΡ… философах), Π½ΠΎ это, ΠΊΠ°ΠΊ Π±Ρ‹Π»ΠΎ ΡƒΠΆΠ΅ сказано, тСорСтичСски ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ΅.

ΠŸΡ€ΠΎ Interlocked стоит ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΌ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ CompareExchange, Π½ΠΎ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ для Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½ΠΎΠ³ΠΎ чтСния И записи. А Ρ‡Π΅Ρ€Π΅Π· ΠΏΠΎΠ²Ρ‚ΠΎΡ€ измСнСния Π² случаС, Ссли Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΠΎΡ‚ΠΎΠΊ успСваСт внСсти свои измСнСния (Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ 1, Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ 2, запись 2, запись 1 плохая), ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ для слоТных ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΎΠ΄Π½ΠΎΠ³ΠΎ значСния (Interlocked Anything ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½).

РСшСния Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ ядра

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ ΠΏΠΎΡ‚Π΅Ρ€ΠΈ рСсурсов Π² Ρ†ΠΈΠΊΠ»Π΅, посмотрим ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΊ. Π”Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, продолТая наш ΠΏΡ€ΠΈΠΌΠ΅Ρ€, посмотрим, ΠΊΠ°ΠΊ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π½Ρ‚ усыпит философа ΠΈ Ρ€Π°Π·Π±ΡƒΠ΄ΠΈΡ‚ Π΅Π³ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚ΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° Π½Π°Π΄ΠΎ. Π‘Π½Π°Ρ‡Π°Π»Π° рассмотрим, ΠΊΠ°ΠΊ это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Ρ€Π΅ΠΆΠΈΠΌ ядра ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмы. ВсС структуры Ρ‚Π°ΠΌ часто ΠΎΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ ΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅, Ρ‡Π΅ΠΌ Ρ‚Π΅, Ρ‡Ρ‚ΠΎ Π² пространствС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. МСдлСннСС Π² нСсколько Ρ€Π°Π·, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ AutoResetEvent ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π² 53 Ρ€Π°Π·Π° ΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅ SpinLock [Π ΠΈΡ…Ρ‚Π΅Ρ€]. Но с ΠΈΡ… ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ процСссы ΠΏΠΎ всСй систСмС, управляСмыС ΠΈΠ»ΠΈ Π½Π΅Ρ‚.

Основная конструкция здСсь это сСмафор, ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ ДСйкстрой Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ»ΡƒΠ²Π΅ΠΊΠ° Π½Π°Π·Π°Π΄. Π‘Π΅ΠΌΠ°Ρ„ΠΎΡ€ это, ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½Π½ΠΎ говоря, ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Ρ†Π΅Π»ΠΎΠ΅ число, управляСмоС систСмой, ΠΈ Π΄Π²Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π½Π° Π½Π΅ΠΌ, β€” ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΡ‚ΡŒ ΠΈ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ. Если ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ Π½Π΅ получаСтся, ноль, Ρ‚ΠΎ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ блокируСтся. Когда число увСличиваСтся ΠΊΠ°ΠΊΠΈΠΌ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠΌ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠΌ/процСссом, Ρ‚ΠΎΠ³Π΄Π° ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΏΡ€ΠΎΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ, Π° сСмафор ΠΎΠΏΡΡ‚ΡŒ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ΡΡ Π½Π° число ΠΏΡ€ΠΎΡˆΠ΅Π΄ΡˆΠΈΡ…. МоТно ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ΅Π·Π΄Π° Π² ΡƒΠ·ΠΊΠΎΠΌ мСстС с сСмафором. .NET ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ нСсколько конструкций с ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹ΠΌΠΈ функциями: AutoResetEvent, ManualResetEvent, Mutex ΠΈ сам Semaphore. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ AutoResetEvent, это самая простая ΠΈΠ· этих конструкций: Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π΄Π²Π° значСния 0 ΠΈ 1 (false, true). Π•Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ WaitOne() Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅Ρ‚ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ, Ссли Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π±Ρ‹Π»ΠΎ 0, Π° Ссли 1, Ρ‚ΠΎ ΠΏΠΎΠ½ΠΈΠΆΠ°Π΅Ρ‚ Π΄ΠΎ 0 ΠΈ пропускаСт Π΅Π³ΠΎ. А ΠΌΠ΅Ρ‚ΠΎΠ΄ Set() ΠΏΠΎΠ²Ρ‹ΡˆΠ°Π΅Ρ‚ Π΄ΠΎ 1 ΠΈ пропускаСт ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰Π΅Π³ΠΎ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠΏΡΡ‚ΡŒ ΠΏΠΎΠ½ΠΈΠΆΠ°Π΅Ρ‚ Π΄ΠΎ 0. ДСйствуСт, ΠΊΠ°ΠΊ Ρ‚ΡƒΡ€Π½ΠΈΠΊΠ΅Ρ‚ Π² ΠΌΠ΅Ρ‚Ρ€ΠΎ.

УслоТним Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΈ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΡƒ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ философа, Π° Π½Π΅ для всСх сразу. Π’.Π΅. Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π΅ΡΡ‚ΡŒ ΠΌΠΎΠ³ΡƒΡ‚ сразу нСсколько философов, Π° Π½Π΅ ΠΎΠ΄ΠΈΠ½. Но ΠΌΡ‹ ΠΎΠΏΡΡ‚ΡŒ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ доступ ΠΊ столу, для Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ, избСгая Π³ΠΎΠ½ΠΎΠΊ (race conditions), Π²Π·ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ.

// Для блокирования ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ философа.
// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ΡΡ: new AutoResetEvent(true) для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ.
private AutoResetEvent[] philosopherEvents;

// Для доступа ΠΊ Π²ΠΈΠ»ΠΊΠ°ΠΌ / доступ ΠΊ столу.
private AutoResetEvent tableEvent = new AutoResetEvent(true);

// Π ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ философа.
public void Run(int i, CancellationToken token)
{
    while (true)
    {
        TakeForks(i); // Π–Π΄Π΅Ρ‚ Π²ΠΈΠ»ΠΊΠΈ.
        // ОбСд. ΠœΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈ дольшС.
        eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
        PutForks(i); // ΠžΡ‚Π΄Π°Ρ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ ΠΈ Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ сосСдСй.
        Think(i);
        if (token.IsCancellationRequested) break;
    }
}

// ΠžΠΆΠΈΠ΄Π°Ρ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ Π² Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ΅.
void TakeForks(int i)
{
    bool hasForks = false;
    while (!hasForks) // ΠŸΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ Π΅Ρ‰Π΅ Ρ€Π°Π· (Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ° Π½Π΅ здСсь).
    {
        // Π˜ΡΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‰ΠΈΠΉ доступ ΠΊ столу, Π±Π΅Π· Π³ΠΎΠ½ΠΎΠΊ Π·Π° Π²ΠΈΠ»ΠΊΠ°ΠΌΠΈ.
        tableEvent.WaitOne();
        if (forks[Left(i)] == 0 && forks[Right(i)] == 0)
            forks[Left(i)] = forks[Right(i)] = i + 1;
        hasForks = forks[Left(i)] == i + 1 && forks[Right(i)] == i + 1;
        if (hasForks)
            // Π’Π΅ΠΏΠ΅Ρ€ΡŒ философ поСст, Π²Ρ‹ΠΉΠ΄Π΅Ρ‚ ΠΈΠ· Ρ†ΠΈΠΊΠ»Π°. Если Set 
            // Π²Ρ‹Π·Π²Π°Π½ Π΄Π²Π°ΠΆΠ΄Ρ‹, Ρ‚ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ true.
            philosopherEvents[i].Set();
        // Π Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰Π΅Π³ΠΎ. ПослС Π½Π΅Π³ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ tableEvent Π² false.
        tableEvent.Set(); 
        // Если ΠΈΠΌΠ΅Π΅Ρ‚ true, Π½Π΅ блокируСтся, Π° Ссли false, Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΆΠ΄Π°Ρ‚ΡŒ Set ΠΎΡ‚ сосСда.
        philosopherEvents[i].WaitOne();
    }
}

// ΠžΡ‚Π΄Π°Ρ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ ΠΈ Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ сосСдСй.
void PutForks(int i)
{
    tableEvent.WaitOne(); // Π‘Π΅Π· Π³ΠΎΠ½ΠΎΠΊ Π·Π° Π²ΠΈΠ»ΠΊΠ°ΠΌΠΈ.
    forks[Left(i)] = 0;
    // ΠŸΡ€ΠΎΠ±ΡƒΠ΄ΠΈΡ‚ΡŒ Π»Π΅Π²ΠΎΠ³ΠΎ, Π° ΠΏΠΎΡ‚ΠΎΠΌ ΠΈ ΠΏΡ€Π°Π²ΠΎΠ³ΠΎ сосСда, Π»ΠΈΠ±ΠΎ AutoResetEvent Π² true.
    philosopherEvents[LeftPhilosopher(i)].Set();
    forks[Right(i)] = 0;
    philosopherEvents[RightPhilosopher(i)].Set();
    tableEvent.Set();
}

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ‚ΡƒΡ‚ происходит, рассмотрим случай, ΠΊΠΎΠ³Π΄Π° философу Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π²Π·ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ, Ρ‚ΠΎΠ³Π΄Π° Π΅Π³ΠΎ дСйствия Π±ΡƒΠ΄ΡƒΡ‚ Ρ‚Π°ΠΊΠΈΠΌΠΈ. Он ΠΆΠ΄Π΅Ρ‚ доступа ΠΊ столу. ΠŸΠΎΠ»ΡƒΡ‡ΠΈΠ² Π΅Π³ΠΎ ΠΎΠ½ ΠΏΡ€ΠΎΠ±ΡƒΠ΅Ρ‚ Π²Π·ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ. НС ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ. Он ΠΎΡ‚Π΄Π°Π΅Ρ‚ доступ ΠΊ столу (Π²Π·Π°ΠΈΠΌΠ½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅). И ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ свой «Ρ‚ΡƒΡ€Π½ΠΈΠΊΠ΅Ρ‚» (AutoResetEvent) (Π²Π½Π°Ρ‡Π°Π»Π΅ ΠΎΠ½ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹). ΠŸΠΎΠΏΠ°Π΄Π°Π΅Ρ‚ ΠΎΠΏΡΡ‚ΡŒ Π² Ρ†ΠΈΠΊΠ», Ρ‚.ΠΊ. Ρƒ Π½Π΅Π³ΠΎ Π½Π΅Ρ‚ Π²ΠΈΠ»ΠΎΠΊ. ΠŸΡ€ΠΎΠ±ΡƒΠ΅Ρ‚ Π²Π·ΡΡ‚ΡŒ ΠΈΡ… ΠΈ останавливаСтся Ρƒ своСго «Ρ‚ΡƒΡ€Π½ΠΈΠΊΠ΅Ρ‚Π°». Какой-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄Π°Ρ‡Π»ΠΈΠ²Ρ‹ΠΉ сосСд справа ΠΈΠ»ΠΈ слСва, Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ² Π΅ΡΡ‚ΡŒ, Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅Ρ‚ нашСго философа, «ΠΎΡ‚крывая Π΅Π³ΠΎ Ρ‚ΡƒΡ€Π½ΠΈΠΊΠ΅Ρ‚». Наш философ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Π΅Π³ΠΎ (ΠΈ ΠΎΠ½ закрываСтся Π·Π° Π½ΠΈΠΌ) Π²ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΉ Ρ€Π°Π·. ΠŸΡ€ΠΎΠ±ΡƒΠ΅Ρ‚ Π² Ρ‚Ρ€Π΅Ρ‚ΠΈΠΉ Ρ€Π°Π· Π²Π·ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ. Π£Π΄Π°Ρ‡Π½ΠΎ. И ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ свой Ρ‚ΡƒΡ€Π½ΠΈΠΊΠ΅Ρ‚, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚ΠΎΠ±Π΅Π΄Π°Ρ‚ΡŒ.

Когда Π² Ρ‚Π°ΠΊΠΎΠΌ ΠΊΠΎΠ΄Π΅ Π±ΡƒΠ΄ΡƒΡ‚ случайныС ошибки (ΠΎΠ½ΠΈ всСгда Π΅ΡΡ‚ΡŒ), Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅Π²Π΅Ρ€Π½ΠΎ ΡƒΠΊΠ°Π·Π°Π½ сосСд ΠΈΠ»ΠΈ создан ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ AutoResetEvent для всСх (Enumerable.Repeat), Ρ‚ΠΎΠ³Π΄Π° философы Π±ΡƒΠ΄ΡƒΡ‚ ΠΆΠ΄Π°Ρ‚ΡŒ ΡƒΠΆΠ΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ², Ρ‚.ΠΊ. поиск ошибок Π² Ρ‚Π°ΠΊΠΎΠΌ ΠΊΠΎΠ΄Π΅ довольно слоТноС занятиС. Π•Ρ‰Ρ‘ ΠΎΠ΄Π½Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° с этим Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΎ Π½Π΅ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΊΠΎΠΉ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ философ Π½Π΅ Π½Π°Ρ‡Π½Π΅Ρ‚ Π³ΠΎΠ»ΠΎΠ΄Π°Ρ‚ΡŒ.

Π“ΠΈΠ±Ρ€ΠΈΠ΄Π½Ρ‹Π΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ

ΠœΡ‹ рассмотрСли Π΄Π²Π° ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° ΠΊ синхронизации, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ остаСмся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈ крутимся Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΈ, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠΎΡ‚ΠΎΠΊ Ρ‡Π΅Ρ€Π΅Π· ядро. ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Ρ…ΠΎΡ€ΠΎΡˆ для ΠΊΡ€Π°Ρ‚ΠΊΠΈΡ… Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΎΠΊ, Π²Ρ‚ΠΎΡ€ΠΎΠΉ для Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ…. Часто трСбуСтся сначала ΠΊΡ€Π°Ρ‚ΠΊΠΎ ΠΎΠΆΠΈΠ΄Π°Ρ‚ΡŒ измСнСния ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π² Ρ†ΠΈΠΊΠ»Π΅, Π° ΠΏΠΎΡ‚ΠΎΠΌ Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΊ, ΠΊΠΎΠ³Π΄Π° ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»Π³ΠΎΠ΅. Π­Ρ‚ΠΎΡ‚ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ Π² Ρ‚.Π½. Π³ΠΈΠ±Ρ€ΠΈΠ΄Π½Ρ‹Ρ… конструкциях. Π—Π΄Π΅ΡΡŒ Π΅ΡΡ‚ΡŒ Ρ‚Π΅ ΠΆΠ΅ конструкции, Ρ‡Ρ‚ΠΎ Π±Ρ‹Π»ΠΈ для Ρ€Π΅ΠΆΠΈΠΌΠ° ядра, Π½ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ с Ρ†ΠΈΠΊΠ»ΠΎΠΌ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ: SemaphorSlim, ManualResetEventSlim ΠΈ Π΄Ρ€. Бамая популярная конструкция здСсь это Monitor, Ρ‚.ΠΊ. Π² C# Π΅ΡΡ‚ΡŒ извСстный всСм lock синтаксис. Monitor это Ρ‚ΠΎΡ‚ ΠΆΠ΅ сСмафор с ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ 1 (ΠΌΡŽΡ‚Π΅ΠΊΡ), Π½ΠΎ с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ оТидания Π² Ρ†ΠΈΠΊΠ»Π΅, рСкурсии, Condition Variable ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½Π° (ΠΎ Π½Π΅ΠΌ Π½ΠΈΠΆΠ΅) ΠΈ Π΄Ρ€. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ с Π½ΠΈΠΌ.

// БпрячСм ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ для ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€Π° ΠΎΡ‚ всСх, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Π΅Π· Π΄Π΅Π΄Π»ΠΎΠΊΠΎΠ².
private readonly object _lock = new object();
// ВрСмя оТидания ΠΏΠΎΡ‚ΠΎΠΊΠ°.
private DateTime?[] _waitTimes = new DateTime?[philosophersAmount];

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

// НашС слоТноС условиС для Condition Variable ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½Π°.
bool CanIEat(int i)
{
    // Если Π΅ΡΡ‚ΡŒ Π²ΠΈΠ»ΠΊΠΈ:
    if (forks[Left(i)] != 0 && forks[Right(i)] != 0)
        return false;
    var now = DateTime.Now;
    // ΠœΠΎΠΆΠ΅Ρ‚, Ссли сосСди Π½Π΅ Π±ΠΎΠ»Π΅Π΅ Π³ΠΎΠ»ΠΎΠ΄Π½Ρ‹Π΅, Ρ‡Π΅ΠΌ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ.
    foreach(var p in new int[] {LeftPhilosopher(i), RightPhilosopher(i)})
        if (_waitTimes[p] != null && now - _waitTimes[p] > now - _waitTimes[i])
            return false;
    return true;
}

void TakeForks(int i)
{
    // Π—Π°ΠΉΡ‚ΠΈ Π² ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€. Π’ΠΎ ΠΆΠ΅ самоС: lock(_lock) {..}.
    // Π’Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Π²Π½Π΅ try, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π²Ρ‹Π±Ρ€Π°ΡΡ‹Π²Π°Π»ΠΎΡΡŒ Π²Ρ‹ΡˆΠ΅.
    bool lockTaken = false;
    Monitor.Enter(_lock, ref lockTaken);
    try
    {
        _waitTimes[i] = DateTime.Now;
        // Condition Variable ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½. ОсвобоТдаСм Π»ΠΎΠΊ, Ссли Π½Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½ΠΎ 
        // слоТноС условиС. И ΠΆΠ΄Π΅ΠΌ ΠΏΠΎΠΊΠ° ΠΊΡ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ сдСлаСт Pulse / PulseAll.
        while (!CanIEat(i))
            Monitor.Wait(_lock); 
        forks[Left(i)] = i + 1;
        forks[Right(i)] = i + 1;
        _waitTimes[i] = null;
    }
    finally
    {
        if (lockTaken) Monitor.Exit(_lock);
    }
}

void PutForks(int i)
{
    // Во ТС самоС: lock (_lock) {..}.
    bool lockTaken = false;
    Monitor.Enter(_lock, ref lockTaken);
    try
    {
        forks[Left(i)] = 0;
        forks[Right(i)] = 0;
        // ΠžΡΠ²ΠΎΠ±ΠΎΠ΄ΠΈΡ‚ΡŒ всС ΠΏΠΎΡ‚ΠΎΠΊΠΈ Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ ΠŸΠžΠ‘Π›Π• Π²Ρ‹Π·ΠΎΠ²Π° Monitor.Exit.
        Monitor.PulseAll(_lock); 
    }
    finally
    {
        if (lockTaken) Monitor.Exit(_lock);
    }
}

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ ΠΎΠΏΡΡ‚ΡŒ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ вСсь стол для доступа ΠΊ Π²ΠΈΠ»ΠΊΠ°ΠΌ, Π½ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ всС сразу ΠΏΠΎΡ‚ΠΎΠΊΠΈ, Π° Π½Π΅ сосСдСй, ΠΊΠΎΠ³Π΄Π° ΠΊΡ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Π΅ΡΡ‚ΡŒ. Π’.Π΅. сначала, ΠΊΡ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Сст ΠΈ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅Ρ‚ сосСдСй, Π° ΠΊΠΎΠ³Π΄Π° этот ΠΊΡ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π΅Ρ‚, Π½ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ сразу ΠΎΠΏΡΡ‚ΡŒ Π΅ΡΡ‚ΡŒ, ΠΎΠ½ ΡƒΡ…ΠΎΠ΄ΠΈΡ‚ Π² Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΡƒ ΠΈ Π±ΡƒΠ΄ΠΈΡ‚ своих сосСдСй, Ρ‚.ΠΊ. Π΅Π³ΠΎ врСмя оТидания мСньшС.

Π’Π°ΠΊ ΠΌΡ‹ ΠΈΠ·Π±Π΅Π³Π°Π΅ΠΌ Π΄Π΅Π΄Π»ΠΎΠΊΠΎΠ² ΠΈ голодания ΠΊΠ°ΠΊΠΎΠ³ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ философа. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ†ΠΈΠΊΠ» для ΠΊΡ€Π°Ρ‚ΠΊΠΎΠ³ΠΎ оТидания ΠΈ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΠΎΡ‚ΠΎΠΊ для Π΄ΠΎΠ»Π³ΠΎΠ³ΠΎ. Π Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ° сразу всСх Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅, Ρ‡Π΅ΠΌ Ссли Π±Ρ‹ Π±Ρ‹Π»Π° Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ сосСда, ΠΊΠ°ΠΊ Π² Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΈ с AutoResetEvent, Π½ΠΎ Ρ€Π°Π·Π½ΠΈΡ†Π° Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ большой, Ρ‚.ΠΊ. ΠΏΠΎΡ‚ΠΎΠΊΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΎΡΡ‚Π°Ρ‚ΡŒΡΡ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ сначала.

Π£ lock синтаксиса Π΅ΡΡ‚ΡŒ нСприятныС ΡΡŽΡ€ΠΏΡ€ΠΈΠ·Ρ‹. Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΡŽΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Monitor Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ [Π ΠΈΡ…Ρ‚Π΅Ρ€] [Π­Ρ€ΠΈΠΊ Π›ΠΈΠΏΠΏΠ΅Ρ€Ρ‚]. Один ΠΈΠ· Π½ΠΈΡ… Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ lock всСгда Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· Monitor, Π΄Π°ΠΆΠ΅ Ссли Π±Ρ‹Π»ΠΎ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, ΠΈ Ρ‚ΠΎΠ³Π΄Π° Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΠΎΡ‚ΠΎΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ состояниС ΠΎΠ±Ρ‰Π΅ΠΉ памяти. Π’ Ρ‚Π°ΠΊΠΈΡ… случаях Ρ‡Π°Ρ‰Π΅ Π»ΡƒΡ‡ΡˆΠ΅ ΡƒΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π² Π΄Π΅Π΄Π»ΠΎΠΊ ΠΈΠ»ΠΈ ΠΊΠ°ΠΊ-Ρ‚ΠΎ бСзопасно Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ. Π”Ρ€ΡƒΠ³ΠΎΠΉ ΡΡŽΡ€ΠΏΡ€ΠΈΠ· Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Monitor ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π±Π»ΠΎΠΊΠΈ синхронизации (SyncBlock), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΅ΡΡ‚ΡŒ Π²ΠΎ всСх ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°Ρ…. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ, Ссли Π²Ρ‹Π±Ρ€Π°Π½ нСподходящий ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΌΠΎΠΆΠ½ΠΎ Π»Π΅Π³ΠΊΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π΄Π΅Π΄Π»ΠΎΠΊ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ссли ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π»ΠΎΠΊ Π½Π° ΠΈΠ½Ρ‚Π΅Ρ€Π½ΠΈΡ€ΠΎΠ²Π°Π½Π½ΡƒΡŽ строку). Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ всСгда скрытый ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ для этого.

Condition Variable ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ позволяСт Π±ΠΎΠ»Π΅Π΅ ΠΊΡ€Π°Ρ‚ΠΊΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ ΠΊΠ°ΠΊΠΎΠ³ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ слоТного условия. Π’ .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 ΠΏΠ΅Ρ€Π²Ρ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠ°, Π° ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π½Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»ΠΈΡΡŒ. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· этих 4 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² простаивал ΠΎΠΊΠΎΠ»ΠΎ 2мс. А Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ с async / await выполняло всС 100, ΠΏΡ€ΠΈ этом Π² срСднСм ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΆΠ΄Π°Π» 6.8 сСкунд. ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π² Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… систСмах простаиваниС ΠΏΠΎ 6 сСкунд Π½Π΅ΠΏΡ€ΠΈΠ΅ΠΌΠ»Π΅ΠΌΠΎ ΠΈ Π»ΡƒΡ‡ΡˆΠ΅ Π½Π΅ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ запросов Ρ‚Π°ΠΊ. РСшСниС ΠΆΠ΅ с Monitor оказалось Π½Π΅ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΌ Π²ΠΎΠΎΠ±Ρ‰Π΅.

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

Как Π²ΠΈΠ΄Π½ΠΎ ΠΈΠ· этих Π½Π΅Π±ΠΎΠ»ΡŒΡˆΠΈΡ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ², .NET ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ ΠΌΠ½ΠΎΠ³ΠΎ конструкций синхронизации. НС всСгда, Π²ΠΏΡ€ΠΎΡ‡Π΅ΠΌ, ΠΎΡ‡Π΅Π²ΠΈΠ΄Π½ΠΎ, ΠΊΠ°ΠΊ ΠΈΡ… ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ. НадСюсь эта ΡΡ‚Π°Ρ‚ΡŒΡ оказалась ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ. Пока Π½Π° этом Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅ΠΌ, Π½ΠΎ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ Π΅Ρ‰Π΅ ΠΌΠ½ΠΎΠ³ΠΎ интСрСсного, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ потокобСзопасныС ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ, TPL Dataflow, Reactive ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅, Software Transaction модСль ΠΈ Π΄Ρ€.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

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

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ