Ndị ọkà ihe ọmụma enwetara nke ọma ma ọ bụ mmemme NET asọmpi

Ndị ọkà ihe ọmụma enwetara nke ọma ma ọ bụ mmemme NET asọmpi

Ka anyị leba anya ka mmemme na-emekọrịta ihe na nke yiri ya si arụ ọrụ na .Net, na-eji ihe atụ nke nsogbu ndị ọkà ihe ọmụma nri ehihie. Atụmatụ a bụ nke a, site na eri / usoro mmekọrịta ruo na onye na-eme ihe nkiri (n'akụkụ ndị a). Edemede a nwere ike ịba uru maka onye mbụ maara ma ọ bụ mee ka ihe ọmụma gị dị ọhụrụ.

Gịnị mere ọbụna mara otú e si eme nke a? Ndị transistors na-erute nha kacha nta, iwu Moore na-akụ oke ọsọ nke ìhè, ya mere a na-ahụ uto na ọnụọgụgụ; N'otu oge ahụ, ọnụọgụ data na-eto eto, ndị ọrụ na-atụkwa anya nzaghachi ozugbo site na usoro. N'ọnọdụ dị otú ahụ, mmemme "nkịtị", mgbe anyị nwere otu eri na-eme ihe, anaghịzi adị irè. Anyị kwesịrị idozi nsogbu nke igbu oge ma ọ bụ n'otu oge. Ọzọkwa, nsogbu a dị na ọkwa dị iche iche: na eriri eri, na usoro nhazi, na ọkwa nke igwe na netwọk (usoro nkesa). NET nwere teknụzụ dị elu, nwalere oge maka idozi nsogbu ndị dị otú ahụ ngwa ngwa na nke ọma.

Ebumnuche

Edsger Dijkstra jụrụ ụmụ akwụkwọ ya nsogbu a laa azụ n'afọ 1965. Nhazi e guzobere bụ nke a. Enwere ọnụ ọgụgụ ụfọdụ (na-abụkarị ise) nke ndị ọkà ihe ọmụma na otu ọnụ ọgụgụ ndụdụ ahụ. Ha na-anọdụ ala na tebụl gburugburu, ndụdụ n'etiti ha. Ndị ọkà ihe ọmụma nwere ike iri na efere ha nke nri na-adịghị agwụ agwụ, chee echiche ma ọ bụ chere. Iji rie nri, onye ọkà ihe ọmụma kwesịrị iburu ndụdụ abụọ (nke ikpeazụ na-ekerịta ndụdụ na nke mbụ). Inweta na ịkwatu ndụdụ bụ omume abụọ dị iche iche. Ndị ọkà ihe ọmụma niile gbachiri nkịtị. Ọrụ a bụ ịchọta algọridim dị otú ahụ ka ha niile chee echiche ma na-eri nri nke ọma ọbụna mgbe afọ 54 gasịrị.

Nke mbụ, ka anyị gbalịa dozie nsogbu a site na iji ohere nkekọrịta. Ndị ndụdụ na-edina na tebụl nkịtị na ndị ọkà ihe ọmụma na-ewere ha mgbe ha nọ ma tinye ha azụ. Nke a bụ ebe nsogbu na mmekọrịta na-ebilite, mgbe kpọmkwem iji ndụdụ? ihe ị ga-eme ma ọ bụrụ na enweghị plọg? wdg Ma buru ụzọ malite na ndị ọkà ihe ọmụma.

Iji malite eri, anyị na-eji ọdọ mmiri threadi via Task.Run usoro:

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

Emebere ọdọ mmiri eri ahụ iji kwalite imepụta na iwepụ eriri. Ọdọ mmiri a nwere ahịrị ọrụ yana CLR na-emepụta ma ọ bụ hichapụ eri dabere na ọnụọgụ ọrụ ndị a. Otu ọdọ mmiri maka AppDomains niile. Ekwesịrị iji ọdọ mmiri a eme ihe fọrọ nke nta ka ọ bụrụ mgbe niile, n'ihi na ... ọ dịghị mkpa ka ị na-echegbu onwe ya na ịmepụta na ihichapụ eri, kwụ n'ahịrị ha, wdg. Ị nwere ike ime ya na-enweghị ọdọ mmiri, ma mgbe ahụ, ị ​​ga-eji ya ozugbo. Thread, Nke a bara uru maka ikpe mgbe anyị kwesịrị ịgbanwe mkpa nke eriri, mgbe anyị na-arụ ọrụ ogologo oge, maka eriri ihu ihu, wdg.

Yabụ, System.Threading.Tasks.Task klas bụ otu Thread, ma n'ụdị ọ bụla dị mma: ikike ịmalite ọrụ mgbe ngọngọ nke ọrụ ndị ọzọ, weghachite ha site na ọrụ, kwụsịtụ ha n'ụzọ dị mfe, na ọtụtụ ndị ọzọ. wdg. Ha dị mkpa iji kwado asynchronous / na-echere ihe owuwu (Ụkpụrụ Asynchronous dabeere na Task, sugar syntactic maka ichere ọrụ IO). Anyị ga-ekwu maka nke a ma emechaa.

CancelationTokenSource ebe a ọ dị mkpa na eriri ahụ nwere ike ịkwụsị onwe ya na mgbama sitere na eriri oku.

Okwu mmekọrịta

Ndị ọkà ihe ọmụma egbochiri

Ọ dị mma, anyị ma ka esi emepụta eri, ka anyị nwaa nri ehihie:

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

N'ebe a, anyị na-ebu ụzọ buru ụzọ were aka ekpe wee were ndụdụ aka nri, ma ọ bụrụ na ọ na-arụ ọrụ, anyị na-eri nri ma tinyeghachi ha. Inwe otu ndụdụ bụ atọmịk, ya bụ. eri abụọ enweghị ike iwere otu n'otu oge (ezighị ezi: nke mbụ na-agụ na ndụdụ dị n'efu, nke abụọ na-eme otu ihe ahụ, nke mbụ na-ewe, nke abụọ na-ewe). Maka nke a Interlocked.CompareExchange, nke a ga-emejuputa atumatu site na iji ntuziaka processor (TSL, XCHG), nke na-akpọchi otu ebe nchekwa maka ịgụ na ide ihe n'usoro atọm. Na SpinWait dabara na ihe owuwu ahụ while(true) naanị na obere "anwansi" - eri ahụ na-ebuli ihe nrụpụta (Thread.SpinWait), ma mgbe ụfọdụ na-enyefe njikwa na eri ọzọ (Thread.Yeild) ma ọ bụ daa ụra (Thread.Sleep).

Mana ngwọta a anaghị arụ ọrụ, n'ihi na ... eri na-adịghị anya (n'ime sekọnd maka m) a na-egbochi: ndị ọkà ihe ọmụma niile na-ewere ndụdụ aka ekpe ha, ma ọ dịghị onye ziri ezi. N'usoro ndụdụ ahụ nwere ụkpụrụ: 1 2 3 4 5.

Ndị ọkà ihe ọmụma enwetara nke ọma ma ọ bụ mmemme NET asọmpi

Na foto a, igbochi eri (mkpọchi). Akwụkwọ ndụ akwụkwọ ndụ na-egosi ogbugbu, uhie na-egosi mmekọrịta, na isi awọ na-egosi na eri ahụ na-arahụ ụra. Ola diamond na-egosi oge mmalite nke Ọrụ.

Agụụ ndị ọkà ihe ọmụma

Ọ bụ ezie na ị chọghị ọtụtụ nri iji chee echiche, agụụ nwere ike ịmanye onye ọ bụla ịhapụ nkà ihe ọmụma. Ka anyi gbaliri ime ka onodu eri eri eri na nsogbu anyi. Agụụ bụ mgbe eri na-arụ ọrụ, ma na-enweghị ọrụ dị ịrịba ama, n'ikwu ya n'ụzọ ọzọ, ọ bụ otu nkwụsị ahụ, naanị ugbu a eri anaghị ehi ụra, ma na-arụsi ọrụ ike na-achọ ihe ọ ga-eri, ma ọ dịghị nri. Iji zere igbochi ugboro ugboro, anyị ga-eweghachi ndụdụ ahụ ma ọ bụrụ na anyị enweghị ike iwere nke ọzọ.

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

Ihe dị mkpa gbasara koodu a bụ na mmadụ abụọ n'ime ndị ọkà ihe ọmụma anọ na-echefu ịkwatu ndụdụ aka ekpe ha. Ọ na-apụta na ha na-erikwu nri, ndị ọzọ na-amalitekwa agụụ, ọ bụ ezie na eri nwere otu ụzọ. N'ebe a, agụụ anaghị agụ ha kpamkpam, n'ihi na ... ndị ọkà ihe ọmụma ọjọọ mgbe ụfọdụ na-eweghachi ndụdụ ha azụ. Ọ na-apụta na ndị ezi nri na-eri ihe dị ka ugboro ise na-erughị ndị ọjọọ. Ya mere, obere njehie na koodu ahụ na-eduga na ọdịda arụmọrụ. N'ebe a, ọ dịkwa mma ịmara na ọnọdụ a na-adịghị ahụkebe ga-ekwe omume mgbe ndị ọkà ihe ọmụma niile na-ewere ndụdụ aka ekpe, ọ dịghị onye ziri ezi, ha na-etinye aka ekpe ala, chere, were aka ekpe ọzọ, wdg. Ọnọdụ a bụkwa agụụ, dị ka mgbochi ibe. Enweghị m ike ikwugharị ya. N'okpuru ebe a bụ foto maka ọnọdụ ebe ndị ọkà ihe ọmụma ọjọọ abụọ ewerela ndụdụ abụọ ahụ, ma ndị abụọ dị mma na-agụ agụụ.

Ndị ọkà ihe ọmụma enwetara nke ọma ma ọ bụ mmemme NET asọmpi

N'ebe a, ị ga-ahụ na eri mgbe ụfọdụ na-eteta ma gbalịa nweta akụrụngwa. Abụọ n'ime cores anọ adịghị eme ihe ọ bụla (graph green n'elu).

Ọnwụ Onye Ọmụma

Ọfọn, otu nsogbu ọzọ nwere ike ịkwụsị nri abalị dị ebube nke ndị ọkà ihe ọmụma bụ ma ọ bụrụ na otu n'ime ha anwụọ na mberede na ndụdụ n'aka ya (a ga-elikwa ya otú ahụ). Mgbe ahụ, ndị agbata obi ga-ahapụ enweghị nri ehihie. Ị nwere ike wepụta koodu ihe atụ maka ikpe a n'onwe gị, dịka ọmụmaatụ a tụfuru ya NullReferenceException mgbe onye ọkà ihe ọmụma were ndụdụ. Ma, n'agbanyeghị, a gaghị edozi ihe ahụ na koodu ọkpụkpọ agaghị ejide ya (maka nke a AppDomain.CurrentDomain.UnhandledException na wdg). Ya mere, a chọrọ ndị na-ahụ maka njehie na eri ahụ n'onwe ha yana njedebe mara mma.

Onye nlekọta

Ọ dị mma, kedu ka anyị ga-esi edozi nsogbu a nke mkpọchi, agụụ na ọnwụ? Anyị ga-ahapụ naanị otu onye ọkà ihe ọmụma na ndụdụ, anyị ga-agbakwunyere ewepu eri maka ebe a. Kedu ka esi eme ya? Ka e were ya na n'akụkụ ndị ọkà ihe ọmụma e nwere onye nlekọta na-enye ikike ka otu onye ọkà ihe ọmụma were ndụdụ. Otu anyị kwesịrị isi mee onye nlekọta a na otú ndị ọkà ihe ọmụma ga-esi jụọ ya bụ ajụjụ na-adọrọ mmasị.

Ụzọ kachasị mfe bụ ka ndị ọkà ihe ọmụma na-ajụkarị onye na-echere maka ịnweta ndụdụ. Ndị ahụ. Ugbu a ndị ọkà ihe ọmụma agaghị echere ndụdụ dị nso, ma chere ma ọ bụ jụọ onye nlekọta ahụ. Na mbụ anyị na-eji naanị Oghere Onye ọrụ maka nke a, anyị anaghị eji nkwụsịtụ kpọọ usoro ọ bụla site na kernel (ọzọ na ha n'okpuru).

Ngwọta oghere onye ọrụ

N'ebe a, anyị ga-eme otu ihe ahụ anyị mere na mbụ na otu ndụdụ na ndị ọkà ihe ọmụma abụọ, anyị ga-atụgharị na akaghị ma chere. Ma ugbu a ọ ga-abụ ndị ọkà ihe ọmụma niile na, dị ka a pụrụ isi kwuo ya, nanị otu ndụdụ, i.e. anyị nwere ike ikwu na ọ bụ naanị onye ọkà ihe ọmụma nke weere "ndụdụ ọla edo" a n'aka onye nlekọta ga-eri nri. Iji mee nke a, anyị na-eji 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 nke a bụ ihe mgbochi, ya na, n'ike n'ike ikwu, otu while(true) { if (!lock) break; }, ma na ọbụna karịa "anwansi" karịa na SpinWait (nke a na-eji ebe ahụ). Ugbu a, ọ maara otú e si agụ ndị na-echere ọnụ, mee ka ha hietụ ụra, na ọtụtụ ihe ndị ọzọ. wdg N'ozuzu, ọ na-eme ihe niile kwere omume iji bulie. Ma anyị ga-echeta na nke a ka bụ otu ihe ahụ na-arụsi ọrụ ike akaghị na-eri ihe processor ego na-ejide a eri, nke nwere ike iduga agụụ ma ọ bụrụ na otu n'ime ndị ọkà ihe ọmụma na-aghọ ihe kacha mkpa karịa ndị ọzọ, ma ọ dịghị nwere ọlaedo ndụdụ (Priority Inversion nsogbu). ). Ya mere, anyị na-eji ya naanị maka mgbanwe dị mkpụmkpụ dị mkpirikpi na ebe nchekwa nkekọrịta, na-enweghị oku ndị ọzọ, mkpọchi akwụkwụ, ma ọ bụ ihe ịtụnanya ndị ọzọ.

Ndị ọkà ihe ọmụma enwetara nke ọma ma ọ bụ mmemme NET asọmpi

Na-ese maka SpinLock. Iyi na-anọgide "na-alụ ọgụ" maka ndụdụ ọla edo. Ọdịda na-eme - mpaghara egosipụtara na ọnụ ọgụgụ ahụ. A naghị eji cores eme ihe nke ọma: naanị ihe dịka 2/3 site na eriri anọ a.

Ihe ngwọta ọzọ ebe a ga-abụ naanị iji Interlocked.CompareExchange na otu nchere na-arụsi ọrụ ike dị ka egosiri na koodu n'elu (na ndị ọkà ihe ọmụma agụụ na-agụ), ma nke a, dị ka e kwuru na mbụ, nwere ike theoretically iduga igbochi.

on Interlocked ọ bara uru ịsị na ọ bụghị naanị CompareExchange, kamakwa ụzọ ndị ọzọ maka ịgụ akwụkwọ na ide ihe. Na site na ịmegharị mgbanwe ahụ, ọ bụrụ na eriri ọzọ na-achịkwa ime mgbanwe ya (gụọ 1, gụọ 2, dee 2, dee 1 dị njọ), enwere ike iji ya mee mgbanwe dị mgbagwoju anya na otu uru (Interlocked Anything pattern).

Ngwọta ọnọdụ kernel

Iji zere imefusị ihe na akaghị aka, ka anyị leba anya ka esi egbochi eri. N'ikwu ya n'ụzọ ọzọ, na-aga n'ihu na ihe atụ anyị, ka anyị hụ otú onye nlekọta ahụ si eme ka onye ọkà ihe ọmụma hie ụra ma kpọtee ya nanị mgbe ọ dị mkpa. Nke mbụ, ka anyị lelee otu esi eme nke a site na ọnọdụ kernel nke sistemụ arụmọrụ. Ihe owuwu niile dị ebe ahụ na-ejikarị nwayọ karịa ndị nọ na oghere onye ọrụ. Ji nwayọọ nwayọọ ọtụtụ ugboro, dịka ọmụmaatụ AutoResetEvent ikekwe 53 ugboro ji nwayọọ nwayọọ SpinLock [Richter]. Mana site na enyemaka ha, ị nwere ike mekọrịta usoro n'ofe sistemụ niile, jisiri ma ọ bụ na ọ bụghị.

Nhazi isi ebe a bụ semaphore, nke Dijkstra tụpụtara ihe karịrị ọkara narị afọ gara aga. A na-etinye semaphore n'ụzọ dị mfe, ọnụọgụ dị mma nke sistemụ na-achịkwa, yana arụ ọrụ abụọ na ya - mmụba na ibelata. Ọ bụrụ na ọ gaghị ekwe omume ibelata efu, mgbe ahụ a na-egbochi eriri oku. Mgbe ọnụọgụ ahụ na-abawanye site na eriri / usoro ọzọ na-arụ ọrụ, mgbe ahụ, a ga-agafe eri ahụ ma na-ebelata semaphore ọzọ site na ọnụọgụ gafere. Ị nwere ike ichetụ n'echiche ụgbọ oloko n'ime ọkpọ nwere semaphore. NET na-enye ọtụtụ ihe nrụpụta nwere ọrụ yiri ya: AutoResetEvent, ManualResetEvent, Mutex na mụ onwe m Semaphore. Anyị ga-eji AutoResetEvent, nke a bụ ihe kachasị mfe n'ime ihe ndị a: naanị ụkpụrụ abụọ 0 na 1 (ụgha, eziokwu). Usoro ya WaitOne() na-egbochi eriri ọkpụkpọ ma ọ bụrụ na uru ya bụ 0, ma ọ bụrụ 1, wetulata ya ka ọ bụrụ 0 wee mafe ya. Usoro Set() na-abawanye ruo 1 ma na-ahapụ otu onye ka ọ gafere, onye ọzọ na-ebelata ka 0. Na-eme ihe dị ka ntụgharị na ụzọ ụgbọ oloko.

Ka anyị na-agbagwoju anya ngwọta na-eji igbochi onye ọ bụla ọkà ihe ọmụma, na ọ bụghị otu mgbe. Ndị ahụ. Ugbu a ọtụtụ ndị ọkà ihe ọmụma nwere ike iri nri ozugbo, ọ bụghị naanị otu. Mana anyị na-egbochikwa ịbanye na tebụl ka anyị wee were ndụdụ nke ọma, na-ezere ọnọdụ agbụrụ.

// Для блокирования отдельного философа.
// Инициализируется: 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();
}

Iji ghọta ihe na-eme ebe a, tụlee ikpe ahụ mgbe onye ọkà ihe ọmụma na-emezughị ndụdụ, mgbe ahụ, omume ya ga-adị ka ndị a. Ọ na-eche ohere ịbanye na tebụl. N'ịbụ onye natara ya, ọ na-agbalị iburu ndụdụ ndị ahụ. Ọ naghị arụ ọrụ. Ọ na-enye ohere ịbanye na tebụl (mwepu ibe ya). Ọ na-agafe “ntụgharị” ya (AutoResetEvent) (na mbụ ha na-emeghe). Ọ na-adaba n'ime okirikiri ọzọ, n'ihi na o nweghị ndụdụ. Ọ na-agbalị ịkpọrọ ha ma kwụsị na "ntụgharị" ya. Ụfọdụ ndị agbata obi nwere ihu ọma n'aka nri ma ọ bụ aka ekpe, ka ha riechara nri, ga-emepe onye ọkà ihe ọmụma anyị site na "imepee ntụgharị ya." Ọkà ihe ọmụma anyị na-agabiga ya (ma ọ na-emechi n'azụ ya) nke ugboro abụọ. Na-agbalị nke ugboro atọ iji were ndụdụ. Na-aga nke ọma. Ọ na-agakwa n'okirikiri ya iri nri ehihie.

Mgbe enwere njehie enweghị usoro na koodu dị otú ahụ (ha na-adị mgbe niile), dịka ọmụmaatụ, a ga-akọwapụta onye agbata obi na-ezighi ezi ma ọ bụ mepụta otu ihe ahụ. AutoResetEvent maka mmadụ niile (Enumerable.Repeat), mgbe ahụ, ndị ọkà ihe ọmụma ga-echere ndị mmepe, n'ihi na Ịchọta mperi na koodu dị otú ahụ bụ ọrụ siri ike. Nsogbu ọzọ na ngwọta a bụ na ọ naghị ekwe nkwa na ụfọdụ ndị ọkà ihe ọmụma agaghị agụ agụụ.

Ngwakọ ngwọta

Anyị lere anya ụzọ abụọ maka mmekọrịta, mgbe anyị na-anọ na onye ọrụ mode na-atụgharị na a akaghị na mgbe anyị na-egbochi eri site kernel. Usoro nke mbụ dị mma maka obere ngọngọ, nke abụọ maka ogologo oge. Ọtụtụ mgbe, ị ga-ebu ụzọ chere obere oge ka mgbanwe gbanwee na loop, wee gbochie eri ahụ mgbe nchere dị ogologo. A na-eme usoro a n'ime ihe a na-akpọ. ngwakọ aghụghọ. Ọ nwere otu ihe nrụpụta dị ka maka ọnọdụ kernel, mana ugbu a jiri akaghị ụdị onye ọrụ: SemaphorSlim, ManualResetEventSlim wdg Ihe kachasị ewu ewu ebe a bụ Monitor, n'ihi na na C # enwere ama ama lock syntax. Monitor nke a bụ otu semaphore na a kacha uru nke 1 (mutex), ma na nkwado maka ichere na a akaghị, recursion, Ọnọdụ mgbanwe ụkpụrụ (ọzọ na na n'okpuru), wdg Ka anyị leba anya na a ngwọta na ya.

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

N'ebe a, anyị na-egbochikwa tebụl ahụ dum ịbanye na ndụdụ, ma ugbu a, anyị na-akpọghee eriri niile n'otu oge, karịa ndị agbata obi mgbe mmadụ richara nri. Ndị ahụ. mbụ, onye nēri ihe na-egbochi agbata obi ya, ma mgbe onye a gụchara, ma chọọ iri nri ọzọ ozugbo, ọ banyere n'ime ụlọ na-akpọte ndị agbata obi ya, n'ihi na. oge nchere ya dị obere.

N'ụzọ dị otú a, anyị na-ezere ịnwụ anwụ na agụụ nke ụfọdụ ndị ọkà ihe ọmụma. Anyị na-eji loop chere obere oge ma gbochie eri ahụ ogologo oge. Ịkpọghe onye ọ bụla n'otu oge dị nwayọọ karịa ma ọ bụrụ na akpọchiri onye agbata obi, dịka na ngwọta ya AutoResetEvent, ma ọdịiche ekwesịghị ịbụ nnukwu, n'ihi na eri ga-adịrịrị na ọnọdụ onye ọrụ.

У lock syntax nwere ụfọdụ ihe ịtụnanya na-adịghị mma. Akwadoro iji Monitor ozugbo [Richter] [Eric Lippert]. Otu n'ime ha bụ nke ahụ lock na-apụta mgbe niile Monitor, ọ bụrụgodị na e nwere ihe dị iche, mgbe ahụ, eriri ọzọ nwere ike ịgbanwe ọnọdụ nke ebe nchekwa nkekọrịta. N'ọnọdụ ndị dị otú ahụ, ọ na-aka mma ịbanye n'ime mkpọchi ma ọ bụ n'ụzọ ụfọdụ kwụsị mmemme ahụ n'enweghị nsogbu. Ihe ịtụnanya ọzọ bụ na Monitor na-eji clock blocks (SyncBlock), nke dị na ihe niile. Ya mere, ọ bụrụ na ahọpụtara ihe na-ekwesịghị ekwesị, ị nwere ike ịnweta mkpọchi n'ụzọ dị mfe (dịka ọmụmaatụ, ọ bụrụ na ị kpọchie na eriri etinyere). Anyị na-eji ihe zoro ezo mgbe niile maka nke a.

Usoro mgbanwe ọnọdụ na-enye gị ohere ịmekwu nkenke nkenke atụmanya nke ọnọdụ ụfọdụ dị mgbagwoju anya. Na NET ezughị ezu, n'echiche m, n'ihi na ... Na tiori, ekwesịrị inwe ọtụtụ kwụ n'ahịrị na ọtụtụ mgbanwe (dị ka ọ dị na Posix Threads), ọ bụghị n'otu mkpọchi. Mgbe ahụ, ọ ga-ekwe omume ịme ha maka ndị ọkà ihe ọmụma niile. Ma ọbụlagodi n'ụdị a ọ na-enye gị ohere ibelata koodu ahụ.

Ọtụtụ ndị ọkà ihe ọmụma ma ọ bụ async / await

Ọ dị mma, ugbu a, anyị nwere ike igbochi eri. Ma gịnị ma ọ bụrụ na anyị nwere ọtụtụ ndị ọkà ihe ọmụma? 100? 10000? Dịka ọmụmaatụ, anyị nwetara arịrịọ 100000 na sava weebụ. Ịmepụta eriri maka arịrịọ ọ bụla ga-adị oke ọnụ, n'ihi na ọtụtụ eri agaghị eme n'otu n'otu. Naanị ka a ga-egbu ọtụtụ cores ezi uche dị na ya (Enwere m 4). Na onye ọ bụla ọzọ ga-ewepụ ihe onwunwe. Otu ngwọta maka nsogbu a bụ usoro async/echere. Echiche ya bụ na ọrụ anaghị ejide eriri ma ọ bụrụ na ọ dị mkpa ichere ka ihe gaa n'ihu. Ma mgbe ihe mere, ọ maliteghachiri ogbugbu ya (ma ọ bụchaghị na otu eri ahụ!). N'ọnọdụ anyị, anyị ga-echere ndụdụ.

SemaphoreSlim nwere maka nke a WaitAsync() usoro. Nke a bụ mmejuputa iwu na-eji ụkpụrụ a.

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

Usoro na async / await a na-asụgharị n'ime ngwa aghụghọ dị oke ala, nke na-eweghachite ya ozugbo Task. Site na ya, ị nwere ike ichere ka usoro ahụ mezue, kagbuo ya na ihe ọ bụla ọzọ ị nwere ike ime na Task. N'ime usoro ahụ, igwe steeti na-achịkwa ogbugbu. Isi ala bụ na ọ bụrụ na ọ dịghị egbu oge, mgbe ahụ ogbugbu ahụ na-emekọrịta ihe, ma ọ bụrụ na ọ dị, a na-ahapụ eri ahụ. Maka nghọta ka mma nke a, ọ ka mma ile anya igwe steeti a. Ị nwere ike ịmepụta agbụ na ndị a async / await ụzọ.

Ka anyị nwalee ya. Ọrụ nke 100 ọkà ihe ọmụma na igwe nwere 4 ezi uche cores, 8 sekọnd. Ngwọta gara aga na Monitor mere naanị eriri 4 nke mbụ ma emeghị nke ọzọ ma ọlị. Nke ọ bụla n'ime eriri 4 ndị a enweghị ọrụ maka ihe dịka 2ms. Na ngwọta async/echere mere 100 niile, yana nkezi nke 6.8 sekọnd ọ bụla chere. N'ezie, na ezigbo sistemu, ịbụ onye na-abaghị uru maka sekọnd 6 bụ ihe anabataghị ma ọ ka mma ịghara ịhazi ọtụtụ arịrịọ n'ụzọ dị otú a. Ihe ngwọta ya na Monitor tụgharịrị bụrụ nke enweghị ike ịgbatị ma ọlị.

nkwubi

Dị ka ị na-ahụ site na obere ihe atụ ndị a, .NET na-akwado ọtụtụ ihe nrụpụta mmekọrịta. Otú ọ dị, ọ bụghị mgbe nile ka ọ na-apụta ìhè ka esi eji ha eme ihe. Enwere m olileanya na akụkọ a bara uru. Anyị na-ekechi nke a maka ugbu a, mana a ka nwere ọtụtụ ihe na-atọ ụtọ fọdụrụ, dịka ọmụmaatụ, mkpokọta nchekwa eri, TPL Dataflow, Reactive programming, Software Transaction model, wdg.

Isi mmalite

isi: www.habr.com

Tinye a comment