Cov kws tshawb fawb tau noj zoo lossis kev sib tw hauv .NET

Cov kws tshawb fawb tau noj zoo lossis kev sib tw hauv .NET

Cia peb saib yuav ua li cas concurrent thiab parallel programming ua haujlwm hauv .Net, siv cov piv txwv ntawm cov teeb meem noj su. Txoj kev npaj yog raws li hauv qab no, los ntawm xov / txheej txheem synchronization rau tus neeg ua yeeb yam qauv (nyob rau hauv cov nram qab no qhov chaw). Kab lus yuav muaj txiaj ntsig zoo rau thawj tus neeg paub lossis ua kom koj cov kev paub tshiab.

Vim li cas thiaj tseem paub ua li no? Transistors tau ncav cuag lawv qhov tsawg kawg nkaus, Moore txoj cai tau tsoo qhov txwv ntawm qhov ceev ntawm lub teeb, thiab yog li ntawd kev loj hlob yog pom nyob rau hauv cov zauv; ntau transistors tuaj yeem ua tau. Nyob rau tib lub sijhawm, cov ntaub ntawv ntau zuj zus, thiab cov neeg siv xav tau cov lus teb tam sim los ntawm cov tshuab. Hauv qhov xwm txheej zoo li no, kev ua haujlwm "ib txwm", thaum peb muaj ib qho kev ua tiav, tsis muaj txiaj ntsig. Peb yuav tsum tau daws qhov teeb meem ntawm kev ua tiav ib txhij lossis ua tiav. Tsis tas li ntawd, qhov teeb meem no tshwm sim nyob rau ntau theem: ntawm qib xov, ntawm theem txheej txheem, ntawm theem ntawm cov cav tov ntawm lub network (distributed systems). .NET muaj cov thev naus laus zis zoo, lub sijhawm sim ua kom sai thiab daws tau cov teeb meem zoo li no.

Hom phiaj

Edsger Dijkstra nug qhov teeb meem no rau nws cov tub ntxhais kawm rov qab rau xyoo 1965. Cov qauv tsim muaj raws li hauv qab no. Muaj qee yam (feem ntau yog tsib) tus lej ntawm cov kws tshawb fawb thiab tib tus lej ntawm rab rawg. Lawv zaum ntawm ib lub rooj puag ncig, diav rawg ntawm lawv. Cov kws tshawb fawb tuaj yeem noj los ntawm lawv daim phiaj ntawm cov zaub mov tsis kawg, xav lossis tos. Txhawm rau noj, tus kws tshaj lij yuav tsum tau nqa ob rab diav rawg (tom kawg sib koom ib rab diav rawg nrog tus qub). Kev khaws thiab tso ib rab diav rawg yog ob txoj haujlwm cais. Tag nrho cov philosophers nyob twj ywm. Lub luag haujlwm yog txhawm rau nrhiav cov algorithm zoo li no kom lawv txhua tus xav thiab noj zoo txawm tias tom qab 54 xyoo.

Ua ntej, cia peb sim daws qhov teeb meem no los ntawm kev siv qhov chaw sib koom. Cov diav rawg dag rau ntawm lub rooj sib tham thiab cov kws tshawb fawb tsuas yog coj lawv thaum lawv nyob ntawd thiab muab lawv rov qab. Qhov no yog qhov teeb meem nrog synchronization tshwm sim, thaum twg raws nraim yuav siv rab diav rawg? yuav ua li cas yog tsis muaj plug? etc. Tab sis ua ntej, cia peb pib nrog cov philosophers.

Yuav pib threads peb siv ib tug xov pas dej ua ke ntawm Task.Run txoj kev:

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);
}

Lub pas dej xov yog tsim los ua kom zoo rau kev tsim thiab tshem tawm cov xov. Lub pas dej no muaj ib kab ntawm cov haujlwm thiab CLR tsim lossis tshem cov xov nyob ntawm seb muaj pes tsawg ntawm cov haujlwm no. Ib lub pas dej rau tag nrho AppDomains. Lub pas dej no yuav tsum siv yuav luag txhua lub sijhawm, vim tias ... Tsis tas yuav thab nrog tsim thiab tshem cov xov, lawv cov kab, thiab lwm yam. Koj tuaj yeem ua nws yam tsis muaj pas dej, tab sis tom qab ntawd koj yuav tau siv nws ncaj qha. Thread, qhov no muaj txiaj ntsig zoo rau cov xwm txheej thaum peb xav tau hloov qhov tseem ceeb ntawm cov xov, thaum peb muaj kev ua haujlwm ntev, rau cov xov Foreground, thiab lwm yam.

Hauv lwm lo lus, System.Threading.Tasks.Task chav kawm yog tib yam Thread, tab sis nrog txhua hom kev yooj yim: lub peev xwm los ua haujlwm tom qab thaiv lwm yam haujlwm, rov qab los ntawm kev ua haujlwm, cuam tshuam lawv yooj yim, thiab ntau ntxiv. thiab lwm yam. Lawv xav tau los txhawb async / tos kev tsim kho (Kev Ua Haujlwm-raws li Asynchronous Pattern, syntactic qab zib rau tos rau kev ua haujlwm IO). Peb mam li tham txog qhov no tom qab.

CancelationTokenSource ntawm no nws yog qhov tsim nyog uas cov xov tuaj yeem txiav nws tus kheej raws li lub teeb liab los ntawm kev hu xov tooj.

Sync teeb meem

Blocked philosophers

Okay, peb paub yuav ua li cas los tsim threads, cia peb noj su:

// ΠšΡ‚ΠΎ ΠΊΠ°ΠΊΠΈΠ΅ Π²ΠΈΠ»ΠΊΠΈ взял. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ: 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();
    }
}

Ntawm no peb thawj zaug sim coj sab laug thiab tom qab ntawd txoj cai nkhaus, thiab yog tias nws ua haujlwm, peb noj thiab muab lawv rov qab. Noj ib rab diav rawg yog atomic, i.e. ob txoj xov tsis tuaj yeem nqa ib qho tib lub sijhawm (tsis yog: thawj nyeem tias rab rawg yog dawb, qhov thib ob ua tib yam, thawj zaug, qhov thib ob siv). Rau qhov no Interlocked.CompareExchange, uas yuav tsum tau muab coj los siv siv cov lus qhia processor (TSL, XCHG), uas kaw ib daim cim xeeb rau atomic sequential nyeem thiab sau ntawv. Thiab SpinWait yog sib npaug rau kev tsim kho while(true) Tsuas yog nrog me ntsis "magic" - xov yuav siv lub processor (Thread.SpinWait), tab sis qee zaum dhau kev tswj mus rau lwm txoj xov (Thread.Yeild) los yog tsaug zog (Thread.Sleep).

Tab sis qhov kev daws teeb meem no tsis ua haujlwm, vim tias ... cov xov sai sai (hauv ib ob rau kuv) raug thaiv: tag nrho cov philosophers coj lawv sab laug diav rawg, tab sis tsis muaj txoj cai. Lub forks array ces muaj qhov tseem ceeb: 1 2 3 4 5.

Cov kws tshawb fawb tau noj zoo lossis kev sib tw hauv .NET

Hauv daim duab, thaiv cov xov (deadlock). Ntsuab qhia txog kev tua, liab qhia synchronization, thiab grey qhia tias xov yog tsaug zog. Pob zeb diamond qhia txog lub sijhawm tso tawm haujlwm.

Kev tshaib kev nqhis ntawm Philosophers

Txawm hais tias koj tsis xav tau ntau yam khoom noj los xav, kev tshaib kev nqhis tuaj yeem yuam kom leej twg tso siab rau kev xav. Cia peb sim simulate qhov xwm txheej ntawm xov tshaib plab hauv peb qhov teeb meem. Kev tshaib kev nqhis yog thaum cov xov ua haujlwm, tab sis tsis muaj kev ua haujlwm tseem ceeb, hauv lwm lo lus, nws yog tib qho kev tuag, tsuas yog tam sim no cov xov tsis tsaug zog, tab sis nquag nrhiav khoom noj, tab sis tsis muaj zaub mov. Txhawm rau kom tsis txhob cuam tshuam ntau zaus, peb yuav muab rab rawg rov qab yog tias peb tsis tuaj yeem nqa lwm tus.

// Π’ΠΎ ΠΆΠ΅ Ρ‡Ρ‚ΠΎ ΠΈ Π² 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)
    );
}

Qhov tseem ceeb ntawm txoj cai no yog tias ob ntawm plaub tus kws tshawb fawb tsis nco qab tso lawv cov diav rawg. Thiab nws hloov tawm tias lawv noj zaub mov ntau dua, thiab lwm tus pib tshaib plab, txawm tias cov xov muaj qhov tseem ceeb. Ntawm no lawv tsis tag tshaib plab, vim ... phem philosophers tej zaum muab lawv rab diav rawg rov qab. Nws hloov tawm tias cov neeg zoo noj li 5 npaug tsawg dua qhov phem. Yog li ib qho yuam kev me me hauv cov cai ua rau kev poob qis hauv kev ua haujlwm. Ntawm no nws tseem tsim nyog sau cia tias qhov xwm txheej tsis tshua muaj tshwm sim thaum txhua tus kws tshawb fawb siv tus nkhaus ntawm sab laug, tsis muaj txoj cai, lawv muab sab laug ib sab, tos, coj sab laug dua, thiab lwm yam. Qhov xwm txheej no kuj yog kev tshaib kev nqhis, zoo li kev sib nrig sib pab. Kuv rov ua tsis tau. Hauv qab no yog ib daim duab rau ib qho xwm txheej uas ob tus neeg xav phem tau coj ob rab diav rawg, thiab ob tus zoo tau tshaib plab.

Cov kws tshawb fawb tau noj zoo lossis kev sib tw hauv .NET

Ntawm no koj tuaj yeem pom tias cov xov qee zaum sawv thiab sim kom tau txais cov peev txheej. Ob ntawm plaub cores tsis ua dab tsi (ntsuab daim duab saum toj no).

Kev tuag ntawm ib tug Philosopher

Zoo, ib qho teeb meem ntxiv uas tuaj yeem cuam tshuam qhov noj hmo zoo kawg nkaus ntawm cov kws tshawb fawb yog tias ib tus ntawm lawv dheev tuag nrog rab rawg hauv nws txhais tes (thiab nws yuav raug faus li ntawd). Ces cov neeg zej zog yuav raug tso tseg tsis noj su. Koj tuaj yeem tuaj nrog tus lej piv txwv rau qhov xwm txheej no koj tus kheej, piv txwv li nws muab pov tseg NullReferenceException tom qab tus philosopher siv rab diav rawg. Thiab, los ntawm txoj kev, qhov kev zam yuav tsis raug daws thiab kev hu xov tooj yuav tsis yooj yim ntes nws (rau qhov no AppDomain.CurrentDomain.UnhandledException thiab lwm yam). Yog li ntawd, yuav tsum tau ua yuam kev handlers nyob rau hauv threads lawv tus kheej thiab nrog graceful txiav.

Lub waiter

Okay, peb yuav daws qhov teeb meem ntawm kev tuag, kev tshaib kev nqhis, thiab kev tuag li cas? Peb yuav tso cai tsuas yog ib tug neeg txawj ntse rau cov diav rawg, thiab peb yuav ntxiv kev sib nrig sib cais ntawm threads rau qhov chaw no. Yuav ua li cas? Xav tias ib sab ntawm cov philosophers muaj ib tug waiter uas tso cai rau ib tug philosopher coj rab rawg. Yuav ua li cas peb yuav tsum ua tus waiter no thiab yuav ua li cas philosophers yuav nug nws yog cov lus nug nthuav.

Txoj kev yooj yim tshaj plaws yog rau cov kws tshawb fawb kom yooj yim tas li nug tus neeg ua haujlwm rau kev nkag mus rau rab rawg. Cov. Tam sim no philosophers yuav tsis tos ib tug diav rawg nyob ze, tab sis tos los yog nug tus waiter. Thaum xub thawj peb tsuas yog siv qhov chaw siv rau qhov no; hauv nws peb tsis siv kev cuam tshuam los hu rau cov txheej txheem los ntawm cov ntsiav (ntxiv rau lawv hauv qab).

Cov neeg siv qhov chaw daws teeb meem

Ntawm no peb yuav ua ib yam dab tsi uas peb tau ua ua ntej nrog ib rab diav rawg thiab ob tus kws tshaj lij, peb yuav tig mus rau hauv lub voj voog thiab tos. Tab sis tam sim no nws yuav yog tag nrho cov philosophers thiab, raws li nws yog, tsuas yog ib tug nkhaus, i.e. peb tuaj yeem hais tias tsuas yog tus kws tshawb fawb uas tau txais qhov "kub diav rawg" ntawm tus neeg tos yuav noj. Txhawm rau ua qhov no peb siv 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 qhov no yog blocker, nrog, roughly hais, tib yam while(true) { if (!lock) break; }, tab sis nrog ntau "magic" ntau dua li hauv SpinWait (uas yog siv nyob ntawd). Tam sim no nws paub yuav ua li cas suav cov neeg tos, muab lawv pw me ntsis, thiab ntau ntxiv. thiab lwm yam. Feem ntau, nws ua txhua yam ua tau kom optimize. Tab sis peb yuav tsum nco ntsoov tias qhov no tseem yog tib lub voj voog uas noj cov khoom siv hluav taws xob thiab tuav cov xov, uas tuaj yeem ua rau kev tshaib kev nqhis yog tias ib qho ntawm cov kws txawj xav ua qhov tseem ceeb tshaj li lwm tus, tab sis tsis muaj qhov kub hnyiab (Priority Inversion teeb meem. ). Yog li ntawd, peb siv nws tsuas yog rau kev hloov pauv luv luv hauv kev sib koom ua ke, tsis muaj kev hu xov tooj thib peb, cov xauv xauv, lossis lwm yam xav tsis thoob.

Cov kws tshawb fawb tau noj zoo lossis kev sib tw hauv .NET

Kev kos duab rau SpinLock. Kwj yog tas li "sib ntaus sib tua" rau golden diav rawg. Failures tshwm sim - qhov chaw tseem ceeb hauv daim duab. Cov cores tsis tau siv tag nrho: tsuas yog li 2/3 los ntawm plaub cov xov no.

Lwm qhov kev daws teeb meem ntawm no tsuas yog siv xwb Interlocked.CompareExchange nrog tib lub sijhawm tos raws li qhia hauv cov cai saum toj no (hauv cov kws tshawb fawb tshaib plab), tab sis qhov no, raws li twb tau hais lawm, tuaj yeem ua rau muaj kev cuam tshuam.

rau Interlocked nws tsim nyog hais tias tsis muaj xwb CompareExchange, tab sis kuj muaj lwm txoj hauv kev rau atomic nyeem ntawv THIAB sau ntawv. Thiab los ntawm kev rov ua dua qhov kev hloov pauv, yog tias lwm txoj xov tswj hwm nws cov kev hloov pauv (nyeem 1, nyeem 2, sau 2, sau 1 tsis zoo), nws tuaj yeem siv rau kev hloov pauv mus rau ib qho nqi (Interlocked Anything pattern).

Kernel hom kev daws teeb meem

Txhawm rau kom tsis txhob nkim cov peev txheej hauv lub voj, cia peb saib yuav ua li cas thaiv cov xov. Hauv lwm lo lus, txuas ntxiv peb tus yam ntxwv, cia saib seb tus neeg tos yuav ua li cas tso tus kws tshawb fawb kom tsaug zog thiab tsa nws thaum tsim nyog. Ua ntej, cia saib yuav ua li cas ua qhov no los ntawm cov ntsiav hom ntawm lub operating system. Tag nrho cov qauv muaj feem ntau xaus qeeb dua li cov neeg siv qhov chaw. Qe ntau zaus, piv txwv li AutoResetEvent tej zaum 53 lub sij hawm qeeb SpinLock [Richter]. Tab sis nrog lawv cov kev pab, koj tuaj yeem synchronize cov txheej txheem thoob plaws tag nrho lub cev, tswj lossis tsis tau.

Cov qauv tsim ntawm no yog ib qho semaphore, tau thov los ntawm Dijkstra ntau tshaj li ib nrab xyoo dhau los. Ib tug semaphore yog, yooj yim muab tso, ib tug zoo integer tswj los ntawm lub system, thiab ob txoj hauj lwm rau nws - nce thiab txo. Yog tias tsis tuaj yeem txo xoom, ces cov xov hu xov tooj raug thaiv. Thaum tus naj npawb tau nce los ntawm qee lwm cov xov / txheej txheem, ces cov xov tau dhau los thiab cov semaphore rov qab los ntawm tus lej dhau. Koj tuaj yeem xav txog cov tsheb ciav hlau hauv lub raj mis nrog lub semaphore. .NET muaj ntau yam tsim nrog cov haujlwm zoo sib xws: AutoResetEvent, ManualResetEvent, Mutex thiab kuv tus kheej Semaphore. Peb yuav siv AutoResetEvent, qhov no yog qhov yooj yim tshaj plaws ntawm cov qauv no: tsuas yog ob qhov txiaj ntsig 0 thiab 1 (false, tseeb). Nws txoj kev WaitOne() thaiv cov xov xov yog tias tus nqi yog 0, thiab yog tias 1, ces demotes nws mus rau 0 thiab hla nws. Ib txoj kev Set() nce mus rau 1 thiab cia ib tug neeg los ntawm, uas dua txo mus rau 0. Ua zoo li ib tug turnstile nyob rau hauv lub subway.

Cia peb nyuaj rau kev daws teeb meem thiab siv kev thaiv rau txhua tus neeg xav, thiab tsis yog rau txhua lub sijhawm. Cov. Tam sim no ntau tus kws tshawb fawb tuaj yeem noj ib zaug, thiab tsis yog ib qho xwb. Tab sis peb rov thaiv kev nkag mus rau lub rooj kom raug coj diav rawg, zam kev sib tw.

// Для блокирования ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ философа.
// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ΡΡ: 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();
}

Yuav kom nkag siab txog qhov tshwm sim ntawm no, xav txog qhov xwm txheej thaum tus kws tshawb fawb ua tsis tiav, ces nws yuav ua raws li hauv qab no. Nws tab tom tos kom nkag mus rau lub rooj. Thaum tau txais nws, nws sim nqa rab rawg. Tsis ua hauj lwm tawm. Nws muab kev nkag mus rau lub rooj (kev sib nrig sib cais). Thiab nws hla nws "turnstile" (AutoResetEvent) (thaum xub qhib lawv). Nws poob rau hauv lub voj voog dua, vim nws tsis muaj forks. Nws sim coj lawv thiab nres ntawm nws "turnstile". Qee tus neeg nyob ze muaj hmoo rau sab xis lossis sab laug, noj mov tas, yuav thaiv peb tus kws tshawb fawb los ntawm "qhib nws lub voj voog." Peb tus kws tshawb fawb dhau los ntawm nws (thiab nws kaw tom qab nws) thib ob. Sim zaum peb mus nqa rab diav rawg. Ua tiav. Thiab nws mus dhau nws txoj kev hloov mus noj su.

Thaum muaj qhov yuam kev tsis raug hauv cov cai no (lawv ib txwm muaj), piv txwv li, ib tus neeg nyob ze yuav raug teev tsis raug lossis tib yam khoom yuav raug tsim. AutoResetEvent rau txhua tus (Enumerable.Repeat), ces cov philosophers yuav tos cov developers, vim Nrhiav qhov yuam kev hauv cov cai no yog ib txoj haujlwm nyuaj heev. Lwm qhov teeb meem nrog qhov kev daws teeb meem no yog tias nws tsis lav tias qee tus kws tshawb fawb yuav tsis tshaib plab.

Hybrid kev daws teeb meem

Peb saib ob txoj hauv kev rau synchronization, thaum peb nyob hauv cov neeg siv hom thiab tig hauv lub voj thiab thaum peb thaiv cov xov los ntawm cov ntsiav. Thawj txoj kev yog zoo rau luv luv blocks, qhov thib ob rau ntev sawv daws yuav. Feem ntau koj yuav tsum xub tos luv luv rau qhov hloov pauv hloov hauv lub voj, thiab tom qab ntawd thaiv cov xov thaum tos ntev. Qhov no txoj kev yog siv nyob rau hauv lub thiaj li hu. hybrid tsim. Nws muaj tib yam tsim raws li hom ntsiav, tab sis tam sim no nrog cov neeg siv hom voj: SemaphorSlim, ManualResetEventSlim thiab lwm yam. Cov qauv nrov tshaj plaws ntawm no yog Monitor, vim nyob rau hauv C# muaj ib tug paub zoo lock syntax. Monitor qhov no yog tib yam semaphore nrog tus nqi siab tshaj plaws ntawm 1 (mutex), tab sis nrog kev txhawb nqa rau kev tos hauv lub voj voog, recursion, Cov xwm txheej tsis sib xws (ntxiv rau qhov hauv qab no), thiab lwm yam. Cia peb saib cov kev daws teeb meem nrog nws.

// БпрячСм ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ для ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€Π° ΠΎΡ‚ всСх, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Π΅Π· Π΄Π΅Π΄Π»ΠΎΠΊΠΎΠ².
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);
    }
}

Ntawm no peb rov thaiv tag nrho lub rooj los ntawm kev nkag mus rau rab rawg, tab sis tam sim no peb tshem tawm tag nrho cov xov ib zaug, tsis yog cov neeg nyob ze thaum ib tus neeg noj mov tas. Cov. ua ntej, ib tug neeg noj thiab thaiv cov neeg nyob ze, thiab thaum tus neeg no ua tiav, tab sis xav noj dua tam sim ntawd, nws nkag mus rau hauv qhov thaiv thiab tsa nws cov neeg nyob ze, vim nws lub sijhawm tos tsawg dua.

Ua li no peb tsis txhob muaj kev tuag thiab kev tshaib kev nqhis ntawm qee tus kws tshawb fawb. Peb siv lub voj voog tos lub sijhawm luv luv thiab thaiv cov xov rau lub sijhawm ntev. Unblocking txhua leej txhua tus ib zaug yog qeeb dua yog tias tsuas yog cov neeg zej zog raug txwv tsis pub, xws li hauv kev daws teeb meem nrog AutoResetEvent, tab sis qhov sib txawv yuav tsum tsis txhob loj, vim threads yuav tsum nyob twj ywm hauv hom neeg siv ua ntej.

Π£ lock syntax muaj qee qhov tsis kaj siab surprises. Pom zoo siv Monitor ncaj qha [Richter] [Eric Lippert]. Ib tug ntawm lawv yog qhov ntawd lock ib txwm tawm los Monitor, txawm tias muaj kev zam, thiab tom qab ntawd lwm cov xov tuaj yeem hloov pauv lub xeev ntawm kev sib koom nco. Nyob rau hauv xws li mob, nws yog feem ntau zoo dua mus rau hauv ib tug deadlock los yog tej yam xyuam xim xaus qhov kev pab cuam. Lwm qhov xav tsis thoob yog tias Monitor siv lub moos thaiv (SyncBlock), uas muaj nyob rau hauv tag nrho cov khoom. Yog li ntawd, yog tias ib qho khoom tsis tsim nyog raug xaiv, koj tuaj yeem tau txais ib qho kev tsis sib haum xeeb (piv txwv li, yog tias koj kaw ntawm txoj hlua interned). Peb ib txwm siv cov khoom zais rau qhov no.

Tus qauv hloov pauv hloov pauv tso cai rau koj kom ua tiav qhov kev cia siab ntawm qee qhov xwm txheej nyuaj. Hauv .NET nws tsis tiav, hauv kuv lub tswv yim, vim tias ... Hauv txoj kev xav, yuav tsum muaj ob peb kab ntawm ntau qhov sib txawv (xws li hauv Posix Xov), thiab tsis yog ntawm ib lub xauv. Ces nws yuav ua tau kom lawv rau tag nrho cov philosophers. Tab sis txawm nyob rau hauv daim ntawv no nws tso cai rau koj kom luv luv code.

Muaj ntau philosophers los yog async / await

Okay, tam sim no peb tuaj yeem thaiv cov xov zoo. Tab sis yuav ua li cas yog tias peb muaj ntau philosophers? 100? 10000? Piv txwv li, peb tau txais 100000 thov rau lub vev xaib server. Tsim ib txoj xov rau txhua qhov kev thov yuav kim, vim ntau threads yuav tsis raug tua nyob rau hauv parallel. Tsuas yog ntau qhov laj thawj yuav raug tua (Kuv muaj 4). Thiab txhua leej txhua tus yuav tsuas tshem tawm cov peev txheej. Ib qho kev daws teeb meem rau qhov teeb meem no yog tus qauv async / tos. Nws lub tswv yim yog tias txoj haujlwm tsis tuav ib txoj xov yog tias nws xav tau tos ib yam dab tsi mus ntxiv. Thiab thaum muaj ib yam dab tsi tshwm sim, nws rov pib nws qhov kev tua (tab sis tsis tas yuav tsum nyob hauv tib txoj xov!). Hauv peb rooj plaub, peb yuav tos ib rab diav rawg.

SemaphoreSlim muaj rau qhov no WaitAsync() txoj kev. Ntawm no yog ib qho kev siv uas siv tus qauv no.

// Запуск Ρ‚Π°ΠΊΠΎΠΉ ΠΆΠ΅, ΠΊΠ°ΠΊ Ρ€Π°Π½ΡŒΡˆΠ΅. Π“Π΄Π΅-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅:
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();
}

Txoj kev nrog async / await yog txhais rau hauv lub cunning finite lub xeev tshuab, uas tam sim ntawd rov qab nws sab hauv Task. Los ntawm nws, koj tuaj yeem tos rau txoj kev ua kom tiav, tshem tawm nws, thiab txhua yam uas koj tuaj yeem ua nrog Task. Hauv txoj kev, lub xeev lub tshuab tswj kev ua tiav. Cov kab hauv qab yog tias yog tsis muaj kev ncua, ces qhov kev ua tiav yog synchronous, thiab yog tias muaj, ces cov xov raug tso tawm. Yog xav paub ntxiv txog qhov no, nws yog qhov zoo dua los saib lub xeev lub tshuab no. Koj tuaj yeem tsim chains los ntawm cov no async / await txoj kev.

Cia peb sim. Ua hauj lwm ntawm 100 philosophers ntawm lub tshuab nrog 4 logical cores, 8 vib nas this. Cov kev daws teeb meem yav dhau los nrog Monitor tsuas yog ua tiav thawj 4 threads thiab tsis ua tiav tag nrho. Txhua ntawm 4 xov no tsis ua haujlwm li 2ms. Thiab qhov kev daws teeb meem async / tos tau ua tag nrho 100, nrog qhov nruab nrab ntawm 6.8 vib nas this txhua tos. Tau kawg, hauv cov tshuab tiag tiag, ua haujlwm rau 6 vib nas this yog qhov tsis txaus ntseeg thiab nws yog qhov zoo dua tsis txhob ua ntau qhov kev thov li no. Qhov kev daws teeb meem nrog Monitor muab tawm los ua tsis tau scalable kiag li.

xaus

Raws li koj tuaj yeem pom los ntawm cov piv txwv me me no, .NET txhawb nqa ntau qhov kev sib koom ua ke. Txawm li cas los xij, nws tsis yog ib txwm pom tseeb tias yuav siv lawv li cas. Kuv vam tias tsab xov xwm no yuav pab tau. Peb tab tom qhwv qhov no rau tam sim no, tab sis tseem muaj ntau cov khoom nthuav tawm, piv txwv li, xov-safe collections, TPL Dataflow, Reactive programming, Software Transaction model, thiab lwm yam.

Cov chaw

Tau qhov twg los: www.hab.com

Ntxiv ib saib