Well-Fed Philosophers kana Competitive .NET Programming

Well-Fed Philosophers kana Competitive .NET Programming

Ngationei kuti hurongwa hunoshanda panguva imwe chete uye hunofambirana sei mu.Net, tichishandisa Philosophers Dining Problem semuenzaniso. Chirongwa ndeichi, kubva pakuwiriranisa kwetambo / maitiro, kune mutambi modhi (mune zvikamu zvinotevera). Nyaya yacho inogona kubatsira kune wekutanga kuzivana kana kuti kumutsiridza ruzivo rwako.

Sei uchizviita zvachose? MaTransistors anosvika pakukura kwavo, mutemo waMoore unogara pakudzikama kwekumhanya kwechiedza uye saka kuwedzera kunoonekwa muhuwandu, mamwe ma transistors anogona kuitwa. Panguva imwecheteyo, huwandu hwe data huri kukura, uye vashandisi vanotarisira mhinduro yekukurumidza kubva kune masisitimu. Mumamiriro ezvinhu akadaro, "yakajairika" hurongwa, kana isu tine imwe tambo yekuuraya, haichashandi. Iwe unofanirwa neimwe nzira kugadzirisa dambudziko rekuita panguva imwe chete kana panguva imwe chete. Uyezve, dambudziko iri riripo pamatanho akasiyana: pamwero wetambo, pamwero wemaitiro, pamwero wemashini mune network (yakagoverwa masisitimu). .NET ine yepamusoro-soro, yakaedzwa nguva-yakaedzwa matekinoroji ekukurumidza uye nemazvo kugadzirisa matambudziko akadaro.

Basa

Edsger Dijkstra akaisa dambudziko iri kuvadzidzi vake kare kare muna 1965. Iyo yakagadzirwa yakagadziriswa ndeyotevera. Pane imwe (kazhinji shanu) nhamba yevazivi uye nhamba imwechete yeforogo. Vanogara patafura yeraundi, forogo pakati pavo. Vazivi vanogona kudya kubva mundiro dzavo dzechikafu chisingaperi, funga kana kumirira. Kuti udye muzivi, unofanira kutora maforogo maviri (yekupedzisira anogovera forogo neyokutanga). Kunhonga nekuisa pasi forogo zvinhu zviviri zvakasiyana. Vese vazivi vakanyarara. Basa nderekutsvaga algorithm yekuti vese vaizofunga uye vazere kunyangwe mushure memakore makumi mashanu nemana.

Kutanga, ngatiedzei kugadzirisa dambudziko iri kuburikidza nekushandisa nzvimbo yakagovaniswa. Maforogo akarara patafura yakajairika uye vazivi vanongoatora pavanenge vari voadzosera. Pano pane matambudziko nekuyananisa, nguva chaiyo yekutora surebets? ko kana pasina forogo? etc. Asi kutanga, ngatitangei vazivi.

Kutanga shinda, tinoshandisa dziva reshinda Task.Run nzira:

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

Dziva reshinda rakagadzirirwa kukwenenzvera kugadzira shinda uye kudzima. Dziva iri rine mutsetse une mabasa uye CLR inogadzira kana kubvisa shinda zvichienderana nehuwandu hwemabasa aya. Dziva rimwe kune ese maAppDomains. Iri dziva rinofanira kushandiswa zvinenge nguva dzose, nokuti. hapana chikonzero chekunetseka nekugadzira, kudzima tambo, mitsetse yavo, nezvimwe. Zvinogoneka pasina dziva, asi zvino unofanirwa kuishandisa zvakananga. Thread, izvi zvinobatsira kune zviitiko kana iwe uchida kushandura kukoshesa kwetambo, kana tine kushanda kwenguva refu, kune Foreground thread, nezvimwewo.

Mune mamwe mazwi, System.Threading.Tasks.Task kirasi yakafanana Thread, asi nemhando dzese dzakareruka: kugona kuita basa mushure mekuvhara kwemamwe mabasa, kuvadzosa kubva kumabasa, zviri nyore kuvakanganisa, nezvimwe. etc. Zvinodiwa kutsigira async / kumirira zvivakwa (Task-based Asynchronous Pattern, syntactic sugar yekumirira IO operations). Tichazotaura nezvazvo gare gare.

CancelationTokenSource apa panodiwa kuti shinda ikwanise kugumira pachiratidzo cheshinda yekudaidza.

Sync Matambudziko

Vakavharirwa Vazivi

Zvakanaka, tinoziva kugadzira shinda, ngatiedzei kudya masikati:

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

Pano isu tinotanga kuedza kutora forogo yekuruboshwe, uye ipapo iyo yakarurama, uye kana ikashanda, saka tinodya uye tinovadzorera zvakare. Kutora forogo imwe atomic, i.e. shinda mbiri haigoni kutora imwe panguva imwe chete (isina kururama: yekutanga inoverenga kuti forogo yakasununguka, yechipiri - zvakare, yekutanga inotora, yechipiri inotora). Nokuda kweizvi Interlocked.CompareExchange, iyo inofanirwa kuitwa nemirairo ye processor (TSL, XCHG), iyo inokiya chidimbu chendangariro chekuverenga nekunyorwa kweatomu. Uye SpinWait yakaenzana nekuvaka while(true) chete ne "mashiripiti" mashoma - tambo inotora processor (Thread.SpinWait), asi dzimwe nguva inoendesa kutonga kune imwe shinda (Thread.Yeild) kana kurara (Thread.Sleep).

Asi mhinduro iyi haishande, nekuti iyo inoyerera nekukurumidza (kwandiri mukati mesekondi) yakavharwa: vese vazivi vanotora yavo yekuruboshwe forogo, asi kwete iyo chaiyo. The forks array zvino ine zvakakosha: 1 2 3 4 5.

Well-Fed Philosophers kana Competitive .NET Programming

Mumufananidzo, kuvhara tambo (deadlock). Green - kuuraya, tsvuku - kuwiriranisa, grey - shinda iri kurara. Iyo rhombuses inoratidza nguva yekutanga yeMabasa.

Nzara yevazivi

Kunyangwe zvisingakodzeri kufunga zvakanyanya chikafu, asi nzara inoita kuti chero munhu arege uzivi. Ngatiedzei kutevedzera mamiriro enzara yeshinda mudambudziko redu. Nzara ndeye apo tambo iri kushanda, asi pasina basa rakakosha, nemamwe mazwi, iyi ndiyo imwechete yakafa, chete ikozvino tambo haisi kurara, asi iri kushingaira kutsvaga chimwe chinhu chekudya, asi hapana chikafu. Kuti tidzivise kuvharika kazhinji, tinodzosera forogo kumashure kana tikatadza kutora imwe.

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

Chinhu chakakosha pamusoro pekodhi iyi ndechekuti vaviri kubva pavana vazivi vanokanganwa kuisa pasi yavo yekuruboshwe forogo. Uye zvinoitika kuti vanodya chikafu chakawanda, asi vamwe vanotanga kufa nenzara, kunyange zvazvo tambo dzichinyanya kukosha. Pano havasi kuziya nenzara zvachose, nokuti. vazivi vakaipa vanoisa maforogo avo kumashure dzimwe nguva. Zvinoitika kuti vanhu vakanaka vanodya kanenge ka5 zvishoma pane zvakaipa. Saka chikanganiso chidiki mukodhi chinotungamira mukudonha kwekuita. Zvakakoshawo kuziva pano kuti mamiriro ezvinhu asingawanzoitiki anokwanisika apo vose vazivi vanotora forogo yekuruboshwe, hapana yakarurama, vanoisa kuruboshwe, kumirira, kutora kuruboshwe zvakare, nezvimwewo. Mamiriro ezvinhu aya zvakare inzara, kufanana nekufa. Ndakatadza kuzvidzokorora. Pasi pane mufananidzo wemamiriro ezvinhu apo mafirosofi maviri akaipa akatora maforogo maviri uye maviri akanaka ari kufa nenzara.

Well-Fed Philosophers kana Competitive .NET Programming

Pano iwe unogona kuona kuti tambo dzinomuka dzimwe nguva uye edza kutora sosi. Maviri emakona mana haaite chinhu (girinhi girafu pamusoro).

Kufa kweMuzivi

Zvakanaka, rimwe dambudziko rinogona kukanganisa kudya kwemanheru kune mbiri yevazivi kana mumwe wavo akafa kamwe kamwe aine maforogo mumaoko ake (uye ivo vachamuviga zvakadaro). Ipapo vavakidzani vachasara vasina kudya kwemanheru. Iwe unogona kuuya nekodhi yemuenzaniso yenyaya iyi iwe pachako, semuenzaniso, inokandwa kunze NullReferenceException mushure mekunge muzivi atora maforogo. Uye, nenzira, iyo yakasarudzika haizobatwa uye iyo yekufona kodhi haingoibata (yeizvi AppDomain.CurrentDomain.UnhandledException uye etc.). Naizvozvo, vanobata kukanganisa vanodiwa mushinda pachayo uye nekugumisira kwakanaka.

Waiter

Zvakanaka, tinogadzirisa sei dambudziko iri rekufa, nzara, uye rufu? Tichabvumira muzivi mumwe chete kuti asvike maforogo, wedzera kusabatanidzwa kwetambo dzenzvimbo ino. Kuzviita sei? Ngatitii pane weta pedyo nevazivi anopa mvumo kune chero muzivi kuti atore maforogo. Tinoita sei muchengeti uyu uye kuti vazivi vachamubvunza sei, mibvunzo inonakidza.

Nzira iri nyore ndeye apo vazivi vanongogara vachibvunza weta kuti awane maforogo. Avo. zvino vazivi havazomirira forogo pedyo, asi mirira kana kubvunza weta. Pakutanga, isu tinoshandisa chete Mushandisi Nzvimbo yeizvi, mairi isu hatishandise kukanganisa kudaidza chero maitiro kubva kukernel (pamusoro pavo pazasi).

Mhinduro munzvimbo yemushandisi

Pano tichaita zvakafanana sezvataimboita neforogo imwe chete nevazivi vaviri, isu tichatenderera mukutenderera uye kumirira. Asi zvino zvichava zvose vazivi uye, sokunge zvakadaro, imwe chete forogo, i.e. zvinogona kutaurwa kuti muzivi chete akatora iyi "forogo yegoridhe" kubva kune weta achadya. Kune izvi isu tinoshandisa 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 ichi chivharo, chine, kutaura, zvakafanana while(true) { if (!lock) break; }, asi nemamwe "mashiripiti" kupfuura mukati SpinWait (iyo inoshandiswa ipapo). Iye zvino anoziva kuverenga vaya vakamirira, ovararisa zvishoma, uye nezvimwe zvakawanda. etc. Kazhinji, anoita zvose zvinobvira kuti optimize. Asi isu tinofanira kuyeuka kuti ichi chichiri chimwechete chinoshanda chinodya processor zviwanikwa uye inochengetedza kuyerera, izvo zvinogona kutungamira kunzara kana mumwe wevazivi akave pamberi kupfuura vamwe, asi asina forogo yegoridhe (Priority Inversion dambudziko) . Naizvozvo, isu tinoishandisa chete kune pfupi pfupi shanduko mundangariro yakagovaniswa, pasina kana yechitatu-bato mafoni, nested makiyi, uye zvimwe zvinoshamisa.

Well-Fed Philosophers kana Competitive .NET Programming

Kudhirowa kwe SpinLock. Hova dzinogara "dzichirwira" forogo yegoridhe. Pane kukundikana - mumufananidzo, nzvimbo yakasarudzwa. Iwo macores haashandiswe zvizere: chete angangoita 2/3 neshinda ina idzi.

Imwe mhinduro pano ingave yekushandisa chete Interlocked.CompareExchange nekumirira kumwechete kunoshanda sezvakaratidzwa mukodhi iri pamusoro (mune vazivi vane nzara), asi izvi, sezvatotaurwa, zvinogona kutungamirira kukuvhara.

pamusoro Interlocked Zvinofanira kucherechedzwa kuti hapana chete CompareExchange, asiwo dzimwe nzira dzeatomu yekuverenga UYE kunyora. Uye kuburikidza nekudzokorora kwekuchinja, kana imwe tambo iine nguva yekuita shanduko yayo (verenga 1, verenga 2, nyora 2, nyora 1 yakaipa), inogona kushandiswa kune dzakaoma shanduko kune imwechete kukosha (Interlocked Anything pattern) .

Kernel Mode Solutions

Kuti tisapambadze zviwanikwa muchiuno, ngationei kuti tingavharisa sei shinda. Nemamwe mashoko, tichienderera mberi nemuenzaniso wedu, ngationei kuti weta anorarisa sei muzivi ndokumumutsa chete pazvinenge zvakakodzera. Kutanga, ngatitarisei maitiro ekuita izvi kuburikidza ne kernel modhi yeiyo inoshanda sisitimu. Zvese zvimiro zviripo kazhinji zvinononoka pane izvo zviri munzvimbo yemushandisi. Kanoverengeka zvishoma nezvishoma, semuenzaniso AutoResetEvent pamwe 53 nguva zvishoma nezvishoma SpinLock [Richter]. Asi nerubatsiro rwavo, unogona kuwiriranisa maitiro mukati mese system, inotungamirwa kana kwete.

Iyo yakakosha kuvaka pano ndiyo semaphore yakakurudzirwa naDijkstra anopfuura hafu yezana ramakore rapfuura. Semaphore iri, nekungoiswa, yakanaka integer inotungamirwa nesystem, uye maviri maoperation pairi, kuwedzera uye kudzikira. Kana ikatadza kudzikira, zero, ipapo tambo yekufona inovharwa. Kana iyo nhamba ichiwedzerwa neimwe tambo inoshanda/maitiro, ipapo tambo dzinosvetuka uye semaphore inodzikiswa zvakare nenhamba yakapfuura. Mumwe anogona kufungidzira zvitima mubhodhoro rine semaphore. .NET inopa akawanda anovaka ane mashandiro akafanana: AutoResetEvent, ManualResetEvent, Mutex uye neni Semaphore. Tichashandisa AutoResetEvent, iyi ndiyo yakapfava yezvivakwa izvi: maviri chete maitiro 0 uye 1 (manyepo, echokwadi). Her Method WaitOne() inovharira tambo yekufona kana kukosha kwaive 0, uye kana 1, inodzikisira kuenda ku0 uye kuisvetuka. Nzira Set() inosimudza kusvika pa1 uye inoregedza weta mumwe chete, anodzika zvakare kusvika ku0. Inoita senzira yepasi pevhu.

Ngatiomese mhinduro uye tishandise kukiya kune mumwe nemumwe muzivi, uye kwete zvese kamwechete. Avo. zvino panogona kuva nevazivi vakawanda panguva imwe chete, uye kwete mumwe. Asi isu zvakare tinovharira kupinda patafura kuitira kuti tiite nemazvo, kudzivirira nhangemutange (madzinza mamiriro), tora surebets.

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

Kuti unzwisise zviri kuitika pano, funga nyaya apo muzivi akakundikana kutora maforogo, ipapo zviito zvake zvichava zvinotevera. Akamirira kusvika patafura. Arigamuchira, anoedza kutora maforogo. Hazvina kushanda. Inopa mukana kune tafura (mutual exclusion). Uye anopfuura "turntile" yake (AutoResetEvent) (vanotanga kuvhurika). Inopinda mudenderedzwa zvakare, nekuti haana maforogo. Anoedza kuvatora omira pa "turnstile" yake. Mumwe muvakidzani ane rombo rakanaka kurudyi kana kuruboshwe, apedza kudya, anovhura muzivi wedu, "kuvhura turnstile yake." Muzivi wedu anoipfuura (uye inovhara kumashure kwayo) kechipiri. Anoedza kechitatu kutora maforogo. Rombo rakanaka. Uye anopfuudza chijana chake kuti adye.

Kana paine zvikanganiso zvisina kujairika mukodhi yakadaro (inogara iripo), semuenzaniso, muvakidzani anotsanangurwa zvisiri izvo kana chinhu chimwe chete chakasikwa. AutoResetEvent kune vese (Enumerable.Repeat), ipapo vazivi vachange vakamirira vanogadzira, nekuti Kutsvaga zvikanganiso mukodhi yakadaro ibasa rakaoma. Rimwe dambudziko nemhinduro iyi nderekuti harivimbisi kuti mumwe muzivi haazonzwe nzara.

Hybrid Solutions

Takatarisa nzira mbiri dzekutora nguva, patinogara mushandisi modhi uye loop, uye patinovhara tambo kuburikidza nekernel. Nzira yekutanga yakanaka kune zvivharo zvipfupi, yechipiri kune yakareba. Zvinowanzodikanwa kutanga muchidimbu kumirira kuti shanduko ichinje muchiuno, uye wozovhara tambo kana kumirira kwakareba. Iyi nzira inoshandiswa mune inonzi. hybrid structures. Heano akafanana ekuvaka senge kernel modhi, asi ikozvino ine mushandisi modhi loop: SemaphorSlim, ManualResetEventSlim etc. Iyo inonyanya kufarirwa dhizaini pano Monitor, nokuti muC# pane inozivikanwa lock syntax. Monitor iyi ndiyo yakafanana semaphore ine huwandu hunokosha hwe1 (mutex), asi nerutsigiro rwekumirira mu loop, recursion, the Condition Variable pattern (zvimwe pane iyo pazasi), nezvimwewo. Ngatitarisei mhinduro nayo.

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

Pano tiri kuvharisa zvakare tafura yese kuti tiwane maforogo, asi ikozvino tiri kuvhura tambo dzese kamwechete, uye kwete vavakidzani kana munhu apedza kudya. Avo. kutanga, mumwe munhu anodya uye anovhara vavakidzani, uye kana uyu munhu apedza, asi anoda kudya zvakare pakarepo, anopinda mukuvhara uye anomutsa vavakidzani vake, nokuti. nguva yayo yekumirira ishoma.

Iyi ndiyo nzira yatinodzivisa nayo kufa uye nzara yemumwe muzivi. Isu tinoshandisa loop yekumirira kwenguva pfupi uye kuvhara tambo kwenguva refu. Kusunungura munhu wese kamwechete kunononoka kupfuura dai muvakidzani chete akavhurwa, semumhinduro AutoResetEvent, asi musiyano haufaniri kuva mukuru, nokuti shinda dzinofanira kugara dziri mushandisi mode kutanga.

Π£ lock syntax ine zvinoshamisa zvinoshamisa. Zvinokurudzira kushandisa Monitor zvakananga [Richter] [Eric Lippert]. Chimwe chazvo ndechokuti lock nguva dzose kunze Monitor, kunyangwe paive nemusiyano, mune iyo nyaya imwe shinda inogona kushandura yakagovaniswa memory state. Mumamiriro ezvinhu akadaro, kazhinji zviri nani kuenda kune deadlock kana neimwe nzira kumisa chirongwa zvakachengeteka. Chimwe chishamiso ndechekuti Monitor inoshandisa mabhuroko ekuyananisa (SyncBlock), izvo zviripo muzvinhu zvese. Naizvozvo, kana chinhu chisina kufanira chakasarudzwa, unogona nyore kuwana deadlock (somuenzaniso, kana iwe ukakiya pane yakavharirwa tambo). Isu tinoshandisa chinhu chakavanzika nguva dzose kune izvi.

Iyo Condition Variable pateni inobvumidza iwe kuti unyatso kuita tarisiro yeimwe yakaoma mamiriro. MuNET, haina kukwana, mumaonero angu, nekuti mudzidziso, panofanirwa kuve nemitsara yakati wandei pane akati wandei (semuPosix Threads), uye kwete pane imwe lok. Ipapo mumwe aigona kuzviita kune vese vazivi. Asi kunyange mune iyi fomu, inokubvumira kuderedza kodhi.

vazivi vakawanda kana async / await

Zvakanaka, ikozvino tinogona kuvharira tambo. Asi zvakadini kana tine vazivi vakawanda? 100? 10000? Semuenzaniso, takagamuchira 100000 zvikumbiro kuwebhu server. Ichave pamusoro kugadzira tambo yechikumbiro chega chega, nekuti saka shinda dzakawanda hadzizomhanye dzakafanana. Inongomhanya yakawanda sekunge paine zvine musoro cores (ini ndine 4). Uye vamwe vese vachangobvisa zviwanikwa. Imwe mhinduro kudambudziko iri ndeye async / yekumirira pateni. Pfungwa yaro ndeyekuti basa haribate shinda kana ichida kumirira kuti chimwe chinhu chienderere mberi. Uye kana ikaita chimwe chinhu, inotangazve kuurayiwa kwayo (asi kwete patambo imwechete!). Kwatiri isu tichamirira forogo.

SemaphoreSlim ane izvi WaitAsync() nzira. Heino kuitisa uchishandisa iyi pateni.

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

Nzira ne async / await inoshandurirwa muchina unonyengera wehurumende uyo pakarepo unodzorera mukati mawo Task. Kuburikidza nayo, unogona kumirira kupedzwa kweiyo nzira, kuibvisa, uye nezvimwe zvese zvaungaite neTask. Mukati menzira, muchina wehurumende unodzora kuuraya. Chinokosha ndechokuti kana pasina kunonoka, ipapo kuurayiwa kunopindirana, uye kana iripo, ipapo tambo inosunungurwa. Kuti unzwisise zviri nani izvi, zviri nani kutarisa iyi muchina wehurumende. Iwe unogona kugadzira maketani kubva kune aya async / await nzira.

Ngatiedze. Basa revazivi ve100 pamushini une 4 logic cores, 8 seconds. Mhinduro yapfuura neMonitor yakangomhanyisa tambo ina dzekutanga uye dzimwe dzese hadzina kumhanya zvachose. Imwe neimwe yeidzi shinda ina yaive isina basa kweinenge 4ms. Uye iyo async / yekumirira mhinduro yakamhanya ese zana, ine avhareji yekumirira ye4 masekonzi imwe neimwe. Ehe, mumasisitimu chaiwo, kusashanda kwemasekonzi matanhatu hakugamuchirwe uye zviri nani kusagadzirisa zvikumbiro zvakawanda seizvi. Mhinduro neMonitor yakazove isina scalable zvachose.

mhedziso

Sezvauri kuona kubva mumienzaniso midiki iyi, .NET inotsigira akawanda ma synchronization anovaka. Zvisinei, hazvisi pachena nguva dzose mashandisirwo azvo. Ndinovimba kuti chinyorwa ichi chakabatsira. Parizvino, uku ndiko kuguma, asi kuchine zvinhu zvakawanda zvinonakidza zvasara, semuenzaniso, kuunganidzwa-kwakachengeteka, TPL Dataflow, Reactive programming, Software Transaction model, nezvimwe.

Sources

Source: www.habr.com

Voeg