Bo-rafilosofi ba Fepang Hantle kapa Competitive .NET Programming

Bo-rafilosofi ba Fepang Hantle kapa Competitive .NET Programming

Ha re boneng hore na mananeo a ts'oanang le a ts'oanang a sebetsa joang ho .Net, ho sebelisa Philosophers Dining Problem e le mohlala. Morero ke ona, ho tloha tumellanong ea likhoele / lits'ebetso, ho ea ho mohlala oa sebapali (likarolong tse latelang). Sengoliloeng se ka ba molemo ho motho oa pele eo u mo tloaetseng kapa ho nchafatsa tsebo ea hau.

Ke hobane'ng ha ho hang? Li-transistors li fihla boholo ba tsona bo fokolang, molao oa Moore o itšetlehile ka moeli oa lebelo la khanya 'me kahoo ho eketseha ho hlokomeloa ka palo, li-transistors tse ngata li ka etsoa. Ka nako e ts'oanang, palo ea data e ntse e eketseha, 'me basebelisi ba lebeletse karabelo ea hang-hang ho tsoa lits'ebetsong. Boemong bo joalo, mananeo a "tloaelehileng", ha re e-na le khoele e le 'ngoe ea ho phethahatsa, ha e sa sebetsa. U hloka ho rarolla bothata ka nako e le 'ngoe kapa ka nako e le 'ngoe. Ho feta moo, bothata bona bo teng maemong a fapaneng: boemong ba likhoele, boemong ba lits'ebetso, boemong ba mechine ea marang-rang (litsamaiso tse ajoang). .NET e na le theknoloji ea boleng bo holimo, e lekiloeng ka nako bakeng sa ho rarolla mathata a joalo kapele le ka katleho.

Sepheo

Edsger Dijkstra o ile a hlahisa bothata bona ho liithuti tsa hae ho tloha ka 1965. Sebopeho se thehiloeng ke se latelang. Ho na le palo e itseng (hangata e mehlano) ea bo-rafilosofi le palo e tšoanang ea lifereko. Ba lula tafoleng e chitja, lifereko li le lipakeng tsa bona. Bo-rafilosofi ba ka ja lipoleiti tsa bona tsa lijo tse sa feleng, ba nahane kapa ba leta. Ho ja rafilosofi, o hloka ho nka lifereko tse peli (ea ho qetela e arolelana fereko le ea pele). Ho nka le ho beha fereko fatše ke liketso tse peli tse fapaneng. Bo-rafilosofi bohle ba khutsitse. Mosebetsi ke ho fumana algorithm e joalo hore kaofela ha bona ba ka e nahana le ho tlala le ka mor'a lilemo tse 54.

Pele, a re lekeng ho rarolla bothata bona ka ho sebelisa sebaka se arolelanoang. Lifereko li lutse tafoleng e tloaelehileng 'me bo-rafilosofi ba li nka feela ha li le teng ebe ba li khutlisetsa. Mona ho na le mathata a ho amahanya, ha hantle ho nka surebets? ho thoe'ng haeba ho se na fereko? etc. Empa pele, a re qaleng bo-rafilosofi.

Ho qala likhoele, re sebelisa letamo la likhoele ho feta Task.Run mokhoa:

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

Letamo la likhoele le etselitsoe ho ntlafatsa tlhahiso ea likhoele le ho hlakola. Letamo lena le na le mokoloko o nang le mesebetsi mme CLR e theha kapa e tlosa likhoele ho latela palo ea mesebetsi ena. Letamo le le leng bakeng sa li-AppDomains tsohle. Letamo lena le lokela ho sebelisoa hoo e ka bang kamehla, hobane. ha ho na tlhoko ea ho khathatseha ka ho theha, ho hlakola likhoele, mela ea bona, joalo-joalo Hoa khoneha ntle le letamo, empa joale u tlameha ho e sebelisa ka kotloloho. Thread, sena se na le thuso bakeng sa linyeoe ha u hloka ho fetola bohlokoa ba khoele, ha re e-na le ts'ebetso e telele, bakeng sa khoele ea Foreground, joalo-joalo.

Ka mantsoe a mang, System.Threading.Tasks.Task sehlopha se tšoana Thread, empa ka mefuta eohle ea boiketlo: bokhoni ba ho tsamaisa mosebetsi ka mor'a ho thibela mesebetsi e meng, ho e khutlisa mesebetsing, ho e sitisa habonolo, le tse ling. joalo-joalo Li hlokahala ho ts'ehetsa meaho ea async / e emetse (Task-based Asynchronous Pattern, tsoekere ea syntactic bakeng sa ho emela ts'ebetso ea IO). Re tla bua ka taba ena hamorao.

CancelationTokenSource mona hoa hlokahala e le hore khoele e ka ikhutsa ka lets'oao la khoele ea mohala.

Sync Mathata

Bo-rafilosofi ba thibetsoeng

Ho lokile, re tseba ho etsa likhoele, ha re lekeng ho ja lijo tsa mots'eare:

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

Mona re qala ho leka ho nka fereko e letšehali, ebe fereko e nepahetseng, 'me haeba e sebetsa, joale rea e ja ebe rea e khutlisetsa. Ho nka fereko e le 'ngoe ke atomic, ke hore. likhoele tse peli li ke ke tsa nka e le 'ngoe ka nako e le' ngoe (e sa nepahalang: ea pele e bala hore fereko e lokolohile, ea bobeli - hape, ea pele e nka, ea bobeli e nka). Molemong oa sena Interlocked.CompareExchange, e tlamehang ho kengoa ts'ebetsong ka taelo ea processor (TSL, XCHG), e notlelang karoloana ea mohopolo bakeng sa ho bala le ho ngola ka tatellano ea liathomo. Mme SpinWait e lekana le moaho while(true) feela ka "boselamose" bo fokolang - khoele e nka processor (Thread.SpinWait), empa ka linako tse ling e fetisetsa taolo ho khoele e 'ngoe (Thread.Yeild) kapa oa robala (Thread.Sleep).

Empa tharollo ena ha e sebetse, hobane phallo haufinyane (ho nna ka hare ho motsotsoana) e koetsoe: bo-rafilosofi bohle ba nka fereko ea bona e letšehali, empa eseng e nepahetseng. The forks array e na le boleng: 1 2 3 4 5.

Bo-rafilosofi ba Fepang Hantle kapa Competitive .NET Programming

Setšoantšong, ho thibela likhoele (deadlock). Botala - ts'ebetso, bofubelu - ho lumellana, bohlooho - khoele e robetse. Li-rhombuse li bontša nako ea ho qala ha Mesebetsi.

Tlala ea Bo-rafilosofi

Le hoja ho sa hlokahale ho nahana haholo-holo lijo tse ngata, empa tlala e etsa hore mang kapa mang a tlohele filosofi. Ha re leke ho etsisa boemo ba tlala ea likhoele bothateng ba rona. Tlala ke ha khoele e ntse e sebetsa, empa ntle le mosebetsi oa bohlokoa, ka mantsoe a mang, ena ke nako e ts'oanang, feela hona joale khoele ha e robale, empa e batla ka mafolofolo ho ja, empa ha ho na lijo. E le ho qoba ho thibela khafetsa, re tla khutlisetsa fereko morao haeba re sa khone ho nka e 'ngoe.

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

Ntho ea bohlokoa ka khoutu ena ke hore bo-rafilosofi ba babeli ho ba bane ba lebala ho beha fereko ea bona e letšehali. 'Me ho hlaha hore ba ja lijo tse ngata, ha ba bang ba qala ho lapa, le hoja likhoele li e-na le tsona tse tlang pele. Mona ha baa lapa ka ho feletseng, hobane. bo-rafilosofi ba babe ba khutlisetsa lifereko tsa bona ka linako tse ling. Hoa etsahala hore batho ba molemo ba ja ka makhetlo a ka bang 5 ho feta ba babe. Kahoo phoso e nyenyane ea khoutu e lebisa ho theoha ha tshebetso. Hape ke habohlokoa ho hlokomela mona hore boemo bo sa tloaelehang bo ka khoneha ha bo-rafilosofi bohle ba nka fereko e letšehali, ha ho na e nepahetseng, ba beha ka ho le letšehali, ba emetse, ba nka le letšehali hape, joalo-joalo. Boemo bona le bona ke tlala ea boja-likata, ho tšoana le ho shoa ha batho. Ke hlolehile ho e pheta. Ka tlaase mona ke setšoantšo sa boemo boo bo-rafilosofi ba babeli ba babe ba nkile lifereko tse peli 'me tse peli tse ntle li bolaoa ke tlala.

Bo-rafilosofi ba Fepang Hantle kapa Competitive .NET Programming

Mona u ka bona hore likhoele li tsoha ka linako tse ling ebe li leka ho fumana mohloli. Li-cores tse peli ho tse 'ne ha li etse letho (graph e tala ka holimo).

Lefu la Rafilosofi

Hantle, bothata bo bong bo ka sitisang lijo tsa mantsiboea tse khanyang tsa bo-rafilosofi ke haeba e mong oa bona a e-shoa ka tšohanyetso a tšoere lifereko matsohong a hae (’me ba tla mo pata joalo). Joale baahelani ba tla sala ba se na lijo tsa motšehare. U ka tla le khoutu ea mohlala bakeng sa nyeoe ena ka bouena, mohlala, e lahleloa ka ntle NullReferenceException ka mor'a hore rafilosofi a nke lifereko. 'Me, ka tsela, mokhelo o ke ke oa sebetsoa mme khoutu ea mohala e ke ke ea e tšoara feela (bakeng sa sena AppDomain.CurrentDomain.UnhandledException le joalo-joalo). Ka hona, ho hlokahala hore ho sebetsanoe le liphoso likhoeleng ka botsona 'me li felisoe ka bokhabane.

Mohoebi

Ho lokile, re ka rarolla bothata bona joang, tlala le lefu? Re tla lumella rafilosofi a le mong feela hore a fihlele lifereko, a kenyelle ka thoko ho likhoele tsa sebaka sena. Joang ho e etsa? A re re ho na le motho ea fanang ka lijo haufi le bo-rafilosofi ea fanang ka tumello ho rafilosofi leha e le ofe hore a nke lifereko. Re etsa motho ea fanang ka lijo joang le hore na bo-rafilosofi ba tla mo botsa joang, lipotso li thahasellisa.

Tsela e bonolo ka ho fetisisa ke ha bo-rafilosofi ba tla lula ba botsa motho ea fanang ka lijo bakeng sa ho fumana lifereko. Tseo. hona joale bo-rafilosofi ba ke ke ba emela fereko e haufi, empa ema kapa ba botse motho ea fanang ka lijo. Qalong, re sebelisa Sebaka sa Mosebelisi feela bakeng sa sena, ho eona ha re sebelise litšitiso ho letsetsa lits'ebetso ho tsoa ho kernel (ka tsona ka tlase).

Litharollo sebakeng sa basebelisi

Mona re tla etsa se tšoanang le seo re neng re se etsa ka fereko e le 'ngoe le bo-rafilosofi ba babeli, re tla potoloha ka potoloho ebe re ema. Empa joale e tla be e le bo-rafilosofi bohle 'me, joalokaha eka ke, fereko e le' ngoe feela, i.e. ho ka boleloa hore ke rafilosofi feela ea ileng a nka "fereko ena ea khauta" ho motho ea fanang ka lijo ea tla ja. Bakeng sa sena re sebelisa 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 sena ke blocker, ka, ha re bua, ka ho tšoana while(true) { if (!lock) break; }, empa ka "boselamose" bo bongata ho feta ho SpinWait (e sebelisoang moo). Joale o tseba ho bala ba letetseng, ho ba robatsa hanyane, le ho feta. joalo-joalo Ka kakaretso, o etsa sohle se matleng a ho ntlafatsa. Empa re tlameha ho hopola hore ena e ntse e le potoloho e ts'oanang e sebetsang e jang lisebelisoa tsa processor le ho boloka phallo, e ka lebisang tlala haeba e mong oa bo-rafilosofi a fetoha ea tlang pele ho feta ba bang, empa a se na fereko ea khauta (Bothata ba Inversion ea Bohlokoa) . Ka hona, re e sebelisa feela bakeng sa liphetoho tse khutšoane haholo mohopolong o arolelanoang, ntle le mehala ea motho oa boraro, liloko tse behiloeng, le lintho tse ling tse makatsang.

Bo-rafilosofi ba Fepang Hantle kapa Competitive .NET Programming

Ho taka bakeng sa SpinLock. Melapo e lula e "loana" bakeng sa fereko ea khauta. Ho na le mefokolo - setšoantšong, sebaka se khethiloeng. Li-cores ha li sebelisoe ka botlalo: ke 2/3 feela ka likhoele tsena tse 'ne.

Tharollo e 'ngoe mona e tla ba ho sebelisa feela Interlocked.CompareExchange ka ho leta ka mafolofolo joalo ka ha ho bonts'itsoe khoutu e kaholimo (ho bo-rafilosofi ba lapileng), empa sena, joalo ka ha se se se boletsoe, se ka lebisa ho thibela.

ka Interlocked Ho lokela ho hlokomeloa hore ha ho na feela CompareExchange, empa le mekhoa e meng ea ho bala LE ho ngola athomo. 'Me ka ho pheta-pheta phetoho, haeba khoele e' ngoe e e-na le nako ea ho etsa liphetoho (bala 1, bala 2, ngola 2, ngola 1 e mpe), e ka sebelisoa bakeng sa liphetoho tse rarahaneng ho boleng bo le bong (Interlocked Anything pattern) .

Litharollo tsa Mokhoa oa Kernel

Ho qoba ho senya lisebelisoa ka har'a lupu, a re boneng hore na re ka thibela khoele joang. Ka mantsoe a mang, ho tsoela pele ka mohlala oa rona, a re boneng hore na mosebeletsi o robatsa rafilosofi joang le ho mo tsosa feela ha ho hlokahala. Taba ea pele, a re shebeng mokhoa oa ho etsa sena ka mokhoa oa kernel oa sistimi e sebetsang. Mehaho eohle e teng hangata e lieha ho feta e sebakeng sa basebelisi. Ka makhetlo a 'maloa butle, mohlala AutoResetEvent mohlomong ka makhetlo a 53 butle SpinLock [Richter]. Empa ka thuso ea bona, o ka hokahanya lits'ebetso ho pholletsa le sistimi, e laoloang kapa che.

Mohaho oa mantlha mona ke semaphore e hlahisitsoeng ke Dijkstra lilemo tse fetang halofo tse fetileng. Semaphore, ka mantsoe a bonolo feela, ke palo e felletseng e laoloang ke sistimi, le lits'ebetso tse peli ho eona, ho eketseha le ho fokotseha. Haeba e hloleha ho fokotseha, zero, joale mohala oa mohala o koetsoe. Ha palo e eketsoa ke khoele / ts'ebetso e 'ngoe e sebetsang, joale likhoele lia tloloa 'me semaphore e boetse e fokotseha ka palo e fetisitsoeng. Motho a ka inahanela literene ka botlolo e nang le semaphore. .NET e fana ka lihahi tse 'maloa tse nang le ts'ebetso e ts'oanang: AutoResetEvent, ManualResetEvent, Mutex le nna Semaphore. Re tla sebelisa AutoResetEvent, ena ke eona e bonolo ka ho fetisisa ea meaho ena: ke litekanyetso tse peli feela 0 le 1 (ea bohata, 'nete). Mokhoa oa Hae WaitOne() e thibela khoele ea mohala haeba boleng e ne e le 0, 'me haeba 1, e theolela ho 0 ebe oa e tlola. Mokhoa Set() e phahamisa ho 1 'me e lumella motho e mong hore a fete, ea theohelang hape ho 0. E sebetsa joalo ka tsela e tsamaeang ka tlas'a lefatše.

Ha re ke re rarahane tharollo 'me re sebelise senotlolo bakeng sa rafilosofi e mong le e mong, eseng ho hang hang. Tseo. hona joale ho ka ba le bo-rafilosofi ba 'maloa ka nako e le' ngoe, eseng a le mong. Empa re boetse re thibela ho fihlella tafoleng e le hore ka nepo, ho qoba merabe (maemo a peiso), nka 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();
}

E le hore u utloisise se etsahalang mona, nahana ka taba ea ha rafilosofi a hlōleha ho nka lifereko, joale liketso tsa hae li tla ba tse latelang. O emetse ho kena tafoleng. Ha a se a e amohetse, o leka ho nka lifereko. Ha ea sebetsa. E fana ka phihlello ea tafole (ho qheleloa ka thoko). 'Me o feta "thibelo" ea hae (AutoResetEvent) (li butsoe qalong). E boela e kena potolohong, hobane ha a na lifereko. O leka ho li nka ebe o emisa "turnstile" ea hae. Moahelani e mong ea nang le mahlohonolo ka ho le letona kapa ka ho le letšehali, ha a qeta ho ja, o bula rafilosofi oa rona, "ho bula mothinya oa hae." Rafilosofi oa rona oa e fetisa ('me e koala ka mor'a eona) lekhetlo la bobeli. O leka ka lekhetlo la boraro ho nka lifereko. Mahlohonolo. 'Me o fetisa thibane ea hae ho ja.

Ha ho na le liphoso tse sa reroang ka khoutu e joalo (li lula li le teng), mohlala, moahelani o hlalositsoe ka phoso kapa ntho e tšoanang e entsoe. AutoResetEvent bakeng sa bohle (Enumerable.Repeat), joale bo-rafilosofi ba tla be ba emetse bahlahisi, hobane Ho fumana liphoso khoutu e joalo ke mosebetsi o boima haholo. Bothata bo bong ka tharollo ena ke hore ha e tiise hore rafilosofi e mong a ke ke a lapa.

Litharollo tsa Hybrid

Re shebile mekhoa e 'meli ea ho beha nako, ha re lula mokhoeng oa mosebelisi le loop, le ha re thibela khoele ka kernel. Mokhoa oa pele o molemo bakeng sa liloko tse khutšoanyane, tsa bobeli bakeng sa tse telele. Hangata hoa hlokahala ho qala ka bokhutšoanyane ho emela hore phetoho e fetohe ka loop, ebe e thibela khoele ha nako e telele e emetse. Mokhoa ona o kengoa tšebetsong ho seo ho thoeng ke. meaho e nyalisitsoeng. Mona ke meaho e ts'oanang le ea kernel mode, empa joale e na le loop ea mosebelisi: SemaphorSlim, ManualResetEventSlim etc. Moralo o tummeng ka ho fetisisa mona ke Monitor, hobane ho C # ho na le e tsebahalang lock syntax. Monitor sena ke semaphore e tšoanang e nang le boleng bo phahameng ba 1 (mutex), empa ka tšehetso ea ho leta ka loop, recursion, Condition Variable paterone (ho feta moo ka tlase), joalo-joalo A re shebeng tharollo le eona.

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

Mona re boetse re thibela tafole eohle bakeng sa ho fumana lifereko, empa joale re notlolla likhoele tsohle hang, eseng baahisani ha motho a qeta ho ja. Tseo. pele, motho oa ja o thiba baahelani, 'me ha motho enoa a qeta, empa a batla ho ja hape hang-hang, o kena ho thibela le ho tsosa baahisani ba hae, hobane. nako ea eona ea ho leta e nyane.

Ena ke tsela eo re qobang ho putlama le tlala ea rafilosofi e mong. Re sebelisa loop bakeng sa ho ema nako e khutšoanyane ebe re thibela khoele nako e telele. Ho notlolla motho e mong le e mong ka nako e le 'ngoe ho lieha ho feta haeba moahelani a ne a sa thijoe, joalo ka tharollo ka AutoResetEvent, empa phapang ha ea lokela ho ba kholo, hobane likhoele li tlameha ho lula maemong a mosebelisi pele.

У lock syntax e na le lintho tse makatsang tse makatsang. Khothalletsa ho sebelisa Monitor ka ho toba [Richter] [Eric Lippert]. E 'ngoe ea tsona ke eona lock kamehla ho tsoa Monitor, le haeba ho ne ho e-na le mokhelo, moo khoele e 'ngoe e ka fetolang boemo ba mohopolo o arolelanoeng. Maemong a joalo, hangata ho molemo ho ea ho deadlock kapa ka tsela e itseng ho felisa lenaneo ka mokhoa o sireletsehileng. Ntho e 'ngoe e makatsang ke hore Monitor e sebelisa li-block tsa khokahano (SyncBlock), tse teng dinthong tsohle. Ka hona, haeba ho khethiloe ntho e sa lokelang, u ka fumana "deadlock" habonolo (mohlala, haeba u notlela khoele e kentsoeng). Re sebelisa ntho e patiloeng kamehla bakeng sa sena.

The Condition Variable Paterone e u lumella ho kenya tšebetsong tebello ea boemo bo itseng bo rarahaneng. Ho .NET, ha e ea phethahala, ka maikutlo a ka, hobane ka khopolo, ho lokela ho ba le mela e 'maloa ka mefuta e mengata (joaloka Posix Threads), eseng ho lok e le' ngoe. Joale motho a ka li etsetsa bo-rafilosofi bohle. Empa esita le ka foromo ena, e u lumella ho fokotsa khoutu.

bo-rafilosofi ba bangata kapa async / await

Ho lokile, joale re ka thibela likhoele hantle. Empa ho thoe’ng haeba re e-na le bo-rafilosofi ba bangata? 100? 10000? Mohlala, re fumane likopo tse 100000 ho seva sa Marang-rang. E tla ba ka holimo ho theha khoele bakeng sa kopo ka 'ngoe, hobane likhoele tse ngata li ke ke tsa matha ka ho bapisa. E tla matha feela kamoo ho nang le li-cores tse utloahalang (ke na le 4). 'Me ba bang kaofela ba tla nka lisebelisoa feela. Tharollo e le 'ngoe bothateng bona ke mokhoa oa async / await. Khopolo ea eona ke hore ts'ebetso ha e ts'oare khoele haeba e hloka ho emela ho hong ho tsoela pele. 'Me ha e etsa ntho e itseng, e tsosolosa ts'ebetso ea eona (empa eseng hakaalo ka khoele e tšoanang!). Tabeng ea rona, re tla emela fereko.

SemaphoreSlim e na le bakeng sa sena WaitAsync() mokhoa. Mona ke ts'ebetsong e sebelisang mokhoa ona.

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

Mokhoa ka async / await e fetoleloa ho mochine oa boemo bo qhekellang oo hang-hang o khutlisetsang ka hare ho oona Task. Ka eona, o ka emela ho phethoa ha mokhoa, oa hlakola, le ntho e ngoe le e ngoe eo u ka e etsang ka Task. Ka hare ho mokhoa, mochine oa mmuso o laola ho bolaoa. Ntlha ea bohlokoa ke hore haeba ho se na tieho, joale ts'ebetso e lumellana, 'me haeba e le teng, joale khoele e lokolloa. Bakeng sa kutloisiso e ntle ea sena, ho molemo ho sheba mochine ona oa mmuso. O ka etsa liketane ho tsoa ho tsena async / await mekhoa.

Ha re lekeng. Mosebetsi oa bo-rafilosofi ba 100 mochine o nang le li-cores tse 4 tse utloahalang, metsotsoana e 8. Tharollo e fetileng ka Monitor e tsamaile likhoele tse 4 tsa pele feela 'me tse ling ha lia ka tsa sebetsa ho hang. E 'ngoe le e 'ngoe ea likhoele tsena tse 4 e ne e sa sebetse nako e ka bang 2ms. 'Me tharollo ea async / e emetse e tsamaile tsohle tse 100, ka karolelano ea ho leta metsotsoana ea 6.8 ka' ngoe. Ehlile, lits'ebetsong tsa 'nete, ho se sebetse ka metsotsoana ea 6 ha ho amohelehe mme ho molemo ho se sebetse likopo tse ngata tse kang tsena. Tharollo ka Monitor e ile ea bonahala e se ntho e mpe ho hang.

fihlela qeto e

Joalokaha u ka bona mehlaleng ena e menyenyane, .NET e tšehetsa lihahi tse ngata tsa ho hokahanya. Leha ho le joalo, hase kamehla ho totobetseng hore na li sebelisoa joang. Ke tšepa hore sehlooho sena se thusitse. Hona joale, ena ke qetello, empa ho ntse ho e-na le lintho tse ngata tse thahasellisang tse setseng, mohlala, likoleke tse sireletsehileng tsa khoele, TPL Dataflow, Reactive programming, Software Transaction model, joalo-joalo.

Mohloli

Source: www.habr.com

Eketsa ka tlhaloso