Faifilosofia Well-Fed po'o Polokalama .NET Competitive

Faifilosofia Well-Fed po'o Polokalama .NET Competitive

Se'i o tatou va'ai pe fa'afefea ona fa'aogaina polokalame fa'atasi ma fa'atusa i le .Net, fa'aaoga le Philosophers Dining Problem e fai ma fa'ata'ita'iga. O le fuafuaga o lenei, mai le faʻamaopoopoina o filo / faiga, i le faʻataʻitaʻiga faʻataʻitaʻiga (i vaega nei). O le tusiga atonu e aoga mo le tagata masani muamua pe ina ia faʻafouina lou malamalama.

Aisea e fai ai? Transistors e oʻo atu i la latou laʻititi laʻititi, o le tulafono a Moore e faʻalagolago i le faʻatapulaʻaina o le saoasaoa o le malamalama ma o le mea lea o se faʻaopoopoga o loʻo matauina i le numera, sili atu transistors e mafai ona faia. I le taimi lava e tasi, o le aofaʻi o faʻamaumauga o loʻo faʻatupulaia, ma o loʻo faʻamoemoeina e tagata faʻaoga se tali vave mai faiga. I se tulaga faapena, "masani" polokalame, pe a tasi le matou filo faʻatinoina, ua le toe aoga. E mana'omia ona e fo'ia le fa'afitauli o le fa'atinoina fa'atasi pe fa'atasi. E le gata i lea, o lenei faʻafitauli o loʻo i ai i tulaga eseese: i le maualuga o filo, i le tulaga o faʻagasologa, i le tulaga o masini i le fesoʻotaʻiga (faʻasalalauga tuʻufaʻatasia). .NET o loʻo iai ni faʻataʻitaʻiga sili ona lelei, faʻataʻitaʻi taimi faʻataʻitaʻiga mo le vave ma le lelei e foia ai ia faʻafitauli.

Faamoemoega

O Edsger Dijkstra na tu'uina atu lenei fa'afitauli i ana tamaiti a'oga i le amataga o le 1965. O le fa'avae fa'avae e fa'apea. E i ai se numera patino (masani e lima) o faifilosofia ma le numera tutusa o tui. Latou te nonofo i se laulau lapotopoto, o tui i lo latou va. E mafai e le au faifilosofia ona 'ai mai a latou ipu meaai e le uma, mafaufau pe faatali. Ina ia 'ai se filosofia, e tatau ona e ave ni tui se lua (o le mea mulimuli e faʻasoa le tui ma le muamua). O le pikiina ma le tu'u i lalo o se tui o ni taga eseese se lua. O faifilosofia uma e leai se pisa. O le galuega o le sailia lea o se algorithm e mafaufau uma i latou ma tumu e tusa lava pe 54 tausaga.

Muamua, tatou taumafai e foia lenei faafitauli e ala i le faʻaogaina o se avanoa faʻasoa. O tui o loʻo taoto i luga o le laulau masani ma naʻo le au faifilosofia e ave pe a iai ma toe faʻafoʻi. O loʻo i ai faʻafitauli i le faʻamaopoopoina, o afea tonu e ave ai surebets? ae faapefea pe a leai se tui? ma isi. Ae muamua, tatou amata le au faifilosofia.

Ina ia amata filo, matou te faʻaaogaina se filo filo i totonu Task.Run auala:

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

O le filo filo ua mamanuina e sili ona lelei le fatuina ma le tapeina o filo. O lenei vaitaele e iai le laina ma galuega ma o le CLR e fatuina pe aveese filo e fuafua i le numera o nei galuega. Tasi vaitaele mo AppDomains uma. O lenei vaitaele e tatau ona faʻaaogaina toetoe lava o taimi uma, aua. e le manaʻomia le faʻalavelave i le fatuina, tapeina o filo, o latou laina, ma isi. E mafai e aunoa ma se vaitaele, ae e tatau ona e faʻaaogaina saʻo. Thread, e aoga lenei mo mataupu pe a manaʻomia le suia o le faʻamuamua o se filo, pe a umi se matou gaioiga, mo se filo i luma, ma isi.

I nisi upu, System.Threading.Tasks.Task vasega e tutusa Thread, ae faʻatasi ai ma ituaiga uma o mea faigofie: o le mafai ona faʻatautaia se galuega pe a uma se poloka o isi galuega, toe faʻafoʻi mai galuega, faʻalavelave faʻalavelave, ma isi mea. ma isi. E mana'omia e lagolago ai faufale async/faatalitali (Task-based Asynchronous Pattern, syntactic sugar mo le fa'atalitali mo galuega IO). O le a tatou talanoaina lenei mea mulimuli ane.

CancelationTokenSource o iinei e manaʻomia ina ia mafai ai e le filo ona muta ia lava i le faʻailoga o le filo valaʻau.

Fa'amatalaga Fa'atasi

Faifilosofia poloka

Lelei, ua tatou iloa le faiga o filo, tatou taumafai e fai le aoauli:

// Кто какие вилки взял. К примеру: 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();
    }
}

O le mea lea tatou te taumafai muamua ai e ave le tui agavale, ona sosoo ai lea ma le tui taumatau, ae a lelei, ona tatou aai ai lea ma toe tuu. O le aveina o le tui e tasi o le atomic, i.e. e lua filo e le mafai ona ave le tasi i le taimi e tasi (sese: o le muamua faitau e leai se totogi, o le lona lua - foi, o le muamua e ave, o le lona lua e ave). Mo lenei Interlocked.CompareExchange, lea e tatau ona faʻatinoina ma se faʻatonuga faʻatonu (TSL, XCHG), lea e lokaina ai se vaega o manatuaga mo le faitau ma le tusitusi faasolosolo atomic. Ma SpinWait e tutusa ma le fausiaina while(true) naʻo sina "togafiti" - o le filo e ave le gaioiga (Thread.SpinWait), ae o nisi taimi e faʻafeiloaʻi ai le pule i se isi filo (Thread.Yeild) pe moe (Thread.Sleep).

Ae e le aoga lenei fofo, aua o le tafe vave (mo aʻu i totonu o le sekone) ua poloka: o faifilosofia uma e ave a latou tui agavale, ae le o le taumatau. O le fa'asologa o tui e iai le tau: 1 2 3 4 5.

Faifilosofia Well-Fed po'o Polokalama .NET Competitive

I le ata, poloka o filo (fa'ato'a). Green - faʻataunuʻu, mumu - synchronization, efuefu - o loʻo momoe le filo. O rhombuses e fa'ailoa mai ai le taimi amata o Galuega.

O le fia aai o Faifilosofia

E ui lava e le manaʻomia le mafaufau aemaise lava le tele o meaʻai, ae o le fiaʻai e faʻaumatia ai e se tasi le filosofia. Sei o tatou taumafai e faataitai le tulaga o le matelaina o filo i la tatou faafitauli. O le matelaina o le taimi lea e taufetuli ai se filo, ae leai se galuega taua, i se isi faaupuga, o le mea lava lea e tasi e mate ai, na o le taimi nei e le o moe le filo, ae o loʻo taumafai e suʻe se meaʻai, ae leai se meaʻai. Ina ia aloese mai le poloka soo, matou te toe tuu i tua le tui pe a le mafai ona matou aveina se isi.

// То же что и в 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)
    );
}

O le mea taua e uiga i lenei tulafono o le lua mai le toafa faifilosofia galo e tuu i lalo o latou tui agavale. Ma e foliga mai latou te 'ai atili i meaʻai, aʻo isi e amata ona matelaina, e ui lava o filo e tutusa le faamuamua. O iinei latou te le o matelaina atoatoa, aua. O faifilosofia leaga e toe tuu a latou tui i nisi taimi. E foliga mai o tagata lelei e 'ai e tusa ma le 5 taimi e itiiti ifo nai lo mea leaga. O lea la o se mea sese laʻititi i le code e taʻitaʻia ai le pa'ū i le faʻatinoga. E taua foi le matauina iinei o se tulaga e seasea tupu pe a ave uma le au faifilosofia i le itu tauagavale, e leai se saʻo, latou te tuʻu le agavale, faʻatali, toe alu i le agavale, ma isi. O lenei tulaga o se matelaina foi, e pei o se faaletonu. Sa ou le toe faia. O loʻo i lalo se ata mo se tulaga lea na ave uma ai e le au faifilosofia leaga e lua ni tui ae lua ni tagata lelei o loʻo matelaina.

Faifilosofia Well-Fed po'o Polokalama .NET Competitive

O iinei e mafai ona e vaʻaia ai o filo e ala i luga i nisi taimi ma taumafai e maua le punaoa. E leai se mea e faia e le lua o le fa (kalafa lanumeamata i luga).

Maliu o se Faifilosofia

Ia, o le isi faʻafitauli e mafai ona faʻalavelaveina se taumafataga mamalu a le au faifilosofia pe a faʻafuaseʻi ona oti se tasi oi latou ma tui i ona lima (ma o le a latou tanumia o ia faapena). Ona tuua ai lea o tuaoi e aunoa ma se taumafataga o le aoauli. E mafai ona e sau ma se faʻataʻitaʻiga code mo lenei mataupu oe lava, mo se faʻataʻitaʻiga, ua lafo i fafo NullReferenceException ina ua uma ona ave e le faifilosofia tui. Ma, i le ala, o le tuusaunoaga o le a le taulimaina ma o le code valaau o le a le na o le puʻeina (mo lenei AppDomain.CurrentDomain.UnhandledException ma isi). O le mea lea, e manaʻomia ni tagata faʻaletonu i totonu o filo latou lava ma faʻamaeʻaina lelei.

Fesoasoani

Lelei, fa'afefea ona tatou fo'ia lenei fa'alavelave, matelaina, ma le oti? Matou te faʻatagaina naʻo le toʻatasi le faifilosofia e oʻo atu i tui, faʻaopoopo le faʻaesea o filo mo lenei nofoaga. E faapefea ona fai? Seʻi faapea o loo tū se auauna i talaane o le ʻaufaifilosofia, o lē na te tuuina atu le faatagaga i so o se tasi o faifilosofia e ave tui. E faʻafefea ona tatou faia lenei tagata faʻatali ma pe faʻafefea ona fesili atu le au faifilosofia ia te ia, o fesili e manaia.

O le auala sili ona faigofie o le taimi e fesili ai le au faifilosofia i taimi uma i le tagata faʻatali mo le avanoa i tui. O na. o lenei o le a le faatali le au faifilosofia mo se tui lata ane, ae faatali pe fesili atu i le auauna. I le taimi muamua, matou te faʻaaogaina naʻo le User Space mo lenei mea, matou te le faʻaogaina faʻalavelave e valaʻau ai soʻo se faiga mai le fatu (e uiga ia i latou i lalo).

Fofo ile avanoa fa'aoga

O iinei o le a tatou faia ai le mea lava e tasi e pei ona masani ai i le tasi tui ma le toʻalua faifilosofia, o le a tatou vili i se taamilosaga ma faʻatali. Ae o lenei o le a avea uma ma faifilosofia ma, e pei ona i ai, na o le tasi le tui, i.e. e mafai ona faapea atu e na o le faifilosofia na ia aveina lenei "tuu auro" mai le auauna o le a 'ai. Mo lenei mea matou te faʻaaogaina 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 o se poloka lea, ma, pe a tautala, tutusa while(true) { if (!lock) break; }, ae e sili atu le "togafiti" nai lo totonu SpinWait (lea e faʻaaogaina iina). O lea la ua ia iloa le faitauina o i latou o loo faatalitali, tuu i latou e momoe teisi, ma isi mea. ma isi. I se tulaga lautele, faia mea uma e mafai e optimize. Ae e tatau ona tatou manatua o le taamilosaga malosi lava lea e tasi e 'ai ai punaoa processor ma tausia le tafe, lea e mafai ona taitai atu ai i le fiaaai pe afai e sili atu le faamuamua o se tasi o le au filosofia nai lo isi, ae leai se tui auro (Priority Inversion problem) . O le mea lea, matou te faʻaaogaina mo naʻo suiga pupuu i mafaufauga fefaʻasoaaʻi, e aunoa ma ni valaʻau lona tolu, loka faʻapipiʻi, ma isi mea e ofo ai.

Faifilosofia Well-Fed po'o Polokalama .NET Competitive

Tusia mo SpinLock. O vaitafe e "tau" pea mo le tui auro. E i ai faʻaletonu - i le ata, le vaega filifilia. E le'o fa'aoga atoatoa le 'au: na'o le 2/3 i nei filo e fa.

O le isi fofo iinei o le na'o le fa'aoga Interlocked.CompareExchange faʻatasi ai ma le faʻatali malosi tutusa e pei ona faʻaalia i le numera o loʻo i luga (i le au faifilosofia matelaina), ae o lenei, e pei ona uma ona fai mai, e mafai ona taʻitaʻia ai le poloka.

i Interlocked E tatau ona maitauina e le gata i lea CompareExchange, ae faapena foi isi auala mo atomic faitau MA tusitusi. Ma e ala i le toe faia o le suiga, i le tulaga o le isi filo e iai le taimi e fai ai ana suiga (faitau 1, faitau 2, tusi 2, tusi 1 leaga), e mafai ona faʻaaogaina mo suiga lavelave i se tau e tasi (Interlocked soʻo se mea mamanu) .

Fofo Fa'atatau Kernel

Ina ia aloese mai le faʻaumatia o punaoa i se matasele, seʻi o tatou vaʻai pe faʻafefea ona tatou poloka se filo. I se isi faaupuga, o le faʻaauauina o la tatou faʻataʻitaʻiga, seʻi o tatou vaʻavaʻai pe faʻafefea ona faʻamoe e le tagata faigaluega le filosofia ma fafagu o ia pe a manaʻomia. Muamua, seʻi o tatou vaʻavaʻai pe faʻapefea ona faia lenei mea e ala i le kernel mode o le faiga faʻaoga. O fausaga uma o lo'o i ai e masani ona fa'agesegese nai lo i latou i avanoa fa'aoga. E tele taimi e fa'agesegese ai, mo se fa'ata'ita'iga AutoResetEvent atonu e 53 taimi lemu SpinLock [Richter]. Ae faʻatasi ai ma la latou fesoasoani, e mafai ona e faʻaogaina faʻagasologa i totonu o le faiga, pulea pe leai.

O le fausaga autu iinei o le semaphore na fuafuaina e Dijkstra i le afa seneturi talu ai. O le semaphore, faigofie lava, o se numera lelei e pulea e le faiga, ma lua gaioiga i luga, faʻaopoopoga ma faʻaititia. Afai e le mafai ona faʻaitiitia, zero, ona poloka lea o le filo valaau. A fa'aopoopo le numera i se isi filo/fa'agaioiga malosi, ona fa'amisi lea o filo ma toe fa'aitiitia le semaphore i le numera na pasia. E mafai e se tasi ona mafaufau i nofoaafi i totonu o se fagu ma se semaphore. .NET o loʻo ofoina atu le tele o fausaga faʻatasi ma galuega faʻatusa: AutoResetEvent, ManualResetEvent, Mutex ma aʻu nei Semaphore. O le a matou faʻaaogaina AutoResetEvent, o le faigofie lea o nei fausaga: naʻo le lua tau 0 ma le 1 (sese, moni). Lana metotia WaitOne() poloka le filo valaau pe afai o le tau o le 0, ae afai 1, tuu i lalo i le 0 ma faamisi. O se metotia Set() si'i i luga i le 1 ma fa'ataga ai se tasi o lo'o fa'atali, e toe fa'amaualalo i le 0. E fai e pei o se ta'avale a lalo.

Sei o tatou faʻalavelaveina le fofo ma faʻaoga le loka mo filosofia taʻitasi, ae le mo mea uma i le taimi e tasi. O na. i le taimi nei e mafai ona i ai le tele o filosofia i le taimi e tasi, ae le o le tasi. Ae matou te toe poloka le avanoa i le laulau ina ia saʻo, aloese mai tuuga (tuuga tuuga), ave 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();
}

Ina ia malamalama i le mea o loʻo tupu iinei, mafaufau i le mataupu pe a le mafai e le faifilosofia ona ave tui, ona faʻapea lea o ana gaioiga. O loʻo ia faʻatali mo se avanoa i le laulau. Ina ua maua, na ia taumafai e ave tui. E lei manuia. E maua ai le avanoa i le laulau (tuufaatasia). Ma pasi atu i lona "turnstile" (AutoResetEvent) (ua tatala muamua). E toe oo atu i le taamilosaga, aua e leai ni ona tui. Na te taumafai e ave i latou ma tu i lana "turnstile". O nisi tuaoi manuia i le itu taumatau po o le agavale, ua uma ona 'ai, tatala lo tatou faifilosofia, "tatala lona turnstile." Na pasi e lo tatou faifilosofia (ma tapunia i tua) mo le taimi lona lua. Na ia taumafai mo le taimi lona tolu e ave tui. Ia maua se laki. Ma na te pasi atu i lana afeafe e ai ai.

Afai ei ai ni mea sese i totonu o ia code (o loʻo i ai i taimi uma), mo se faʻataʻitaʻiga, e le saʻo le faʻamaonia o se tuaoi pe faia le mea lava e tasi AutoResetEvent mo tagata uma (Enumerable.Repeat), ona faatalitali lea o le au faifilosofia mo le au atiaʻe, aua O le sailia o mea sese i ia code o se galuega faigata tele. O le isi faʻafitauli i lenei fofo e le faʻamautinoa ai o le a le fia 'ai se faifilosofia.

Fofo Fa'asusu

Ua matou vaʻavaʻai i auala e lua i le taimi, pe a matou tumau i le faʻaoga faʻaoga ma le matasele, ma pe a matou poloka filo i le fatu. O le auala muamua e lelei mo loka pupuu, o le lona lua mo umi. E masani ona manaʻomia le faʻatali mo sina taimi mo se fesuiaiga e sui i se matasele, ona poloka lea o le filo pe a umi le faʻatali. O lenei faiga e faʻatinoina i le mea e taʻua. fausaga fefiloi. O mea ia e tasi e pei o le kernel mode, ae o lea ua i ai se faʻaoga faʻaoga faʻaoga: SemaphorSlim, ManualResetEventSlim ma isi. Le mamanu sili ona lauiloa iinei o Monitor, ona i le C # o loʻo i ai se lauiloa lock syntax. Monitor o le semaphore lava lea e tasi ma le maualuga maualuga o le 1 (mutex), ae faʻatasi ai ma le lagolago mo le faʻatali i totonu o se matasele, toe faʻafoʻi, o le Condition Variable pattern (sili atu i lalo ifo), ma isi. Seʻi o tatou vaʻai i se fofo ma ia.

// Спрячем объект для Монитора от всех, чтобы без дедлоков.
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);
    }
}

O lea ua tatou toe poloka le laulau atoa mo le avanoa i tui, ae o lea ua tatou tatalaina uma filo i le taimi e tasi, ae le o tuaoi pe a uma se tasi e ai. O na. muamua, 'ai se tasi ma poloka le tuaoi, ma a uma lenei tagata, ae manao e toe 'ai i le taimi lava lea, na ia alu i le poloka ma fafagu i luga o ona tuaoi, aua. e itiiti lona taimi faatalitali.

O le auala lea tatou te aloese ai mai le faʻalavelave ma le matelaina o nisi o faifilosofia. Matou te faʻaogaina se matasele mo se faʻatali puupuu ma poloka le filo mo se umi umi. O le tatalaina o tagata uma i le taimi e tasi e telegese nai lo le na o le tuaoi na tatalaina, pei o le fofo ma AutoResetEvent, ae le tatau ona tele le eseesega, aua e tatau ona tumau filo i le tulaga fa'aoga muamua.

У lock syntax ei ai ni fa'ate'ia leaga. Fautuaina e fa'aoga Monitor tuusao [Richter] [Eric Lippert]. O se tasi o latou o lena lock i fafo i taimi uma Monitor, e tusa lava pe i ai se tuusaunoaga, i le tulaga lea e mafai ai e se isi filo ona suia le tulaga o mafaufauga faʻasoa. I ia tulaga, e masani ona sili atu le alu i le faʻamaʻi poʻo le faʻamutaina saogalemu o le polokalama. O le isi mea e ofo ai o le Monitor e faʻaaogaina poloka faʻatasi (SyncBlock), o loʻo iai i mea uma. O le mea lea, afai e filifilia se mea le talafeagai, e faigofie ona e maua se faʻamaʻi (mo se faʻataʻitaʻiga, pe a e lokaina i luga o se manoa faʻaoga). Matou te faʻaogaina le mea masani natia mo lenei mea.

O le Condition Variable pattern e mafai ai ona e fa'atinoina fa'atotonugalemu le fa'amoemoe o nisi tulaga lavelave. I le .NET, e le atoatoa, i loʻu manatu, ona i le teori, e tatau ona i ai ni laina i luga o le tele o fesuiaiga (pei o le Posix Threads), ae le o le tasi lok. Ona mafai lea e se tasi ona faia mo tagata faifilosofia uma. Ae e oʻo lava i lenei fomu, e faʻatagaina oe e faʻaititia le code.

le tele o faifilosofia po o async / await

Lelei, ua mafai nei ona tatou poloka lelei filo. Ae faʻapefea pe afai e toʻatele a tatou faifilosofia? 100? 10000? Mo se faʻataʻitaʻiga, na matou mauaina 100000 talosaga i le upega tafaʻilagi. O le a fa'auluulu e fai se filo mo talosaga ta'itasi, aua o le tele o filo o le a le fetaui. O le a naʻo le tele o loʻo i ai faʻamatalaga talafeagai (e iai aʻu 4). Ma o isi tagata uma o le a na ona aveesea punaoa. Ole tasi fofo ile fa'afitauli ole async/wait pattern. O lona manatu e le taofia e le galuega le filo pe a manaʻomia le faʻatali mo se mea e faʻaauau. Ma pe a faia se mea, e toe faʻaauau lona faʻatinoga (ae le o le filo lava e tasi!). I lo tatou tulaga, o le a tatou faatali mo le tui.

SemaphoreSlim e iai mo lenei mea WaitAsync() auala. O se faʻatinoga lea e faʻaaoga ai lenei mamanu.

// Запуск такой же, как раньше. Где-нибудь в программе:
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();
}

Metotia ma async / await ua faaliliuina i totonu o se masini malo taufaasese lea e vave ona toe faafoi mai lona totonu Task. E ala i ai, e mafai ona e faʻatali mo le maeʻa o le metotia, faʻaleaogaina, ma isi mea uma e mafai ona e faia i le Task. I totonu o le metotia, e pulea e le masini a le setete le faʻatinoga. O le laina pito i lalo e faapea afai e leai se faatuai, o lona uiga o le faatinoga o le synchronous, ma afai ei ai, ona tatala lea o le filo. Mo se malamalama sili atu i lenei mea, e sili atu le vaʻai i lenei masini setete. E mafai ona e faia ni filifili mai nei mea async / await metotia.

Tatou faataitai. Galuega a le au faifilosofia e 100 i luga o se masini ma 4 autu talafeagai, 8 sekone. O le fofo muamua ma le Monitor na o le 4 filo muamua na tamomoe ae o le isi e leʻi tamoe. O nei filo e 4 sa leai se aoga mo le tusa ma le 2ms. Ma o le async / faʻatali tali na alu uma 100, faʻatasi ai ma le averesi faʻatali o le 6.8 sekone taʻitasi. O le mea moni, i faiga moni, e le taliaina mo le 6 sekone ma e sili atu le le faʻatinoina o le tele o talosaga e pei o lenei. O le fofo ma le Monitor na foliga mai e le mafai ona faʻaogaina.

iʻuga

E pei ona mafai ona e vaʻai mai i nei faʻataʻitaʻiga laiti, .NET lagolagoina le tele o faʻasologa faʻatulagaina. Ae ui i lea, e le o taimi uma e iloa ai pe faʻapefea ona faʻaaogaina. Ou te faʻamoemoe sa fesoasoani lenei tusiga. Mo le taimi nei, o le iuga lea, ae o loʻo i ai pea le tele o mea manaia o loʻo totoe, mo se faʻataʻitaʻiga, faʻaputuga o filo-saogalemu, TPL Dataflow, Reactive programming, Software Transaction model, ma isi.

Punaoa

puna: www.habr.com

Faaopoopo i ai se faamatalaga