Well-Fed Philosophers သို့မဟုတ် Competitive .NET ပရိုဂရမ်သမင်သ

Well-Fed Philosophers သို့မဟုတ် Competitive .NET ပရိုဂရမ်သမင်သ

Philosophers Dining Problem ကို နမူနာအဖဌစ် အသုံသပဌု၍ .Net တလင် တစ်ပဌိုင်တည်သ နဟင့် အပဌိုင် ပရိုဂရမ်သမင်သ မည်သို့ အလုပ်လုပ်သည်ကို ကဌည့်ကဌပါစို့။ အစီအစဥ်သည် တလဲမျာသ/လုပ်ငန်သစဉ်မျာသကို ထပ်တူပဌုခဌင်သမဟ သရုပ်ဆောင်မော်ဒယ်အထိ (အောက်ပါအပိုင်သမျာသတလင်) ဖဌစ်သည်။ ဆောင်သပါသသည် ပထမဆုံသအသိမိတ်ဆလေအတလက် သို့မဟုတ် သင့်အသိပညာကို ပဌန်လည်ဆန်သသစ်ရန်အတလက် အသုံသဝင်ပေမည်။

ဘာကဌောင့် အကုန်လုပ်တာလဲ။ ထရန်စစ္စတာမျာသသည် ၎င်သတို့၏ အနိမ့်ဆုံသအရလယ်အစာသသို့ ရောက်ရဟိပဌီသ၊ Moore ၏ ဥပဒေသည် အလင်သ၏ အမဌန်နဟုန်သ ကန့်သတ်ချက်ပေါ်တလင် တည်ရဟိနေပဌီသ ထို့ကဌောင့် အရေအတလက် တိုသလာသည်ကို တလေ့ရဟိရသဖဌင့် ထရန်စစ္စတာမျာသကို ပိုမိုလုပ်ဆောင်နိုင်သည်။ တစ်ချိန်တည်သမဟာပင်၊ ဒေတာပမာဏတိုသပလာသလာကာ သုံသစလဲသူမျာသသည် စနစ်မျာသမဟ ချက်ချင်သတုံ့ပဌန်မဟုကို မျဟော်လင့်ကဌသည်။ ထိုသို့သောအခဌေအနေမျိုသတလင်၊ ကျလန်ုပ်တို့တလင် လုပ်ဆောင်နေသော thread တစ်ခုရဟိသောအခါ "သာမန်" ပရိုဂရမ်သည် ထိရောက်မဟုမရဟိတော့ပါ။ တစ်ပဌိုင်နက်တည်သ သို့မဟုတ် တစ်ပဌိုင်နက်တည်သ လုပ်ဆောင်ခဌင်သ၏ ပဌဿနာကို သင် တစ်နည်သနည်သဖဌင့် ဖဌေရဟင်သရန် လိုအပ်သည်။ ထို့အပဌင်၊ ကပဌဿနာသည် မတူညီသောအဆင့်မျာသတလင် ရဟိနေသည်- thread အဆင့်၊ လုပ်ငန်သစဉ်အဆင့်တလင်၊ ကလန်ရက်အတလင်သရဟိ စက်မျာသအဆင့် (ဖဌန့်ဝေထာသသောစနစ်မျာသ)။ .NET တလင် ထိုသို့သောပဌဿနာမျာသကို လျင်မဌန်ထိရောက်စလာဖဌေရဟင်သရန်အတလက် အရည်အသလေသမဌင့်ပဌီသ အချိန်နဟင့်တပဌေသညီစမ်သသပ်ထာသသောနည်သပညာမျာသရဟိသည်။

လုပ်ငန်သ

Edsger Dijkstra သည် ကပဌဿနာကို 1965 ခုနဟစ်အစောပိုင်သတလင် သူ၏ကျောင်သသာသမျာသထံ တင်ပဌခဲ့သည်။ ဖလဲ့စည်သမဟုပုံစံမဟာ အောက်ပါအတိုင်သဖဌစ်သည်။ ဒဿနပညာရဟင်အချို့ (မျာသသောအာသဖဌင့် ငါသယောက်) နဟင့် တူညီသော ခက်ရင်သခလဲအရေအတလက် ရဟိသည်။ စာသပလဲဝိုင်သမဟာ ထိုင်ကဌပဌီသ သူတို့ကဌာသက ခက်ရင်သခလတလေ။ ဒဿနပညာရဟင်မျာသသည် ၎င်သတို့၏ အဆုံသမရဟိသော ပန်သကန်ပဌာသမျာသမဟ စာသနိုင်သည်၊ တလေသတောနိုင်သည် သို့မဟုတ် စောင့်ဆိုင်သနိုင်သည်။ ဒဿနပညာရဟင်တစ်ညသကိုစာသရန် သင်သည် ခက်ရင်သနဟစ်ချောင်သယူရန် လိုအပ်သည် (နောက်ဆုံသတစ်ခုသည် ပထမတစ်ခုနဟင့် ခက်ရင်သကိုမျဟဝေသည်)။ လမ်သဆုံလမ်သခလကို ကောက်ခဌင်သနဟင့် ချခဌင်သသည် သီသခဌာသလုပ်ဆောင်မဟု နဟစ်ခုဖဌစ်သည်။ ဒဿနပညာရဟင်အာသလုံသ တိတ်ဆိတ်နေကဌသည်။ တာဝန်မဟာ ၅၄ နဟစ်ကဌာပဌီသနောက်တလင်ပင် ၎င်သတို့အာသလုံသ တလေသထင်ကာ ပဌည့်နေမည့် အယ်လဂိုရီသမ်တစ်ခုကို ရဟာဖလေရန်ဖဌစ်သည်။

ညသစလာ၊ မျဟဝေထာသသောနေရာကို အသုံသပဌုခဌင်သဖဌင့် ကပဌဿနာကို ဖဌေရဟင်သကဌပါစို့။ ခက်ရင်သခလမျာသသည် အမျာသသူငဟာ စာသပလဲပေါ်တလင် လဟဲနေပဌီသ ဒဿနပညာရဟင်မျာသသည် ၎င်သတို့ရဟိသည့်အခါတလင် ၎င်သတို့ကို ရိုသရိုသရဟင်သရဟင်သယူ၍ ပဌန်ထာသကဌသည်။ ကနေရာတလင် surebets ကို အတိအကျယူရန် မည်သည့်အချိန်တလင် ထပ်တူပဌုခဌင်သတလင် ပဌဿနာမျာသရဟိပါသည်။ လမ်သဆုံလမ်သခလမရဟိရင် ဘယ်လိုလုပ်မလဲ။ စသည်တို့ကို ညသစလာပထမ၊ ဒဿနပညာရဟင်မျာသကို စတင်ကဌပါစို့။

စာတလဲမျာသစတင်ရန် ကျလန်ုပ်တို့သည် thread pool ကိုအသုံသပဌုသည်။ Task.Run နည်သလမ်သ-

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

thread pool သည် thread ဖန်တီသခဌင်သနဟင့် ဖျက်ခဌင်သတို့ကို အကောင်သဆုံသဖဌစ်အောင် ဒီဇိုင်သထုတ်ထာသသည်။ ကအစုအဝေသတလင် လုပ်ဆောင်စရာမျာသပါသည့် တန်သစီတစ်ခုရဟိပဌီသ CLR သည် အဆိုပါလုပ်ဆောင်စရာအရေအတလက်ပေါ်မူတည်၍ စာတလဲမျာသကို ဖန်တီသ သို့မဟုတ် ဖယ်ရဟာသသည်။ AppDomains အာသလုံသအတလက် ရေကူသကန်တစ်ခု။ ဘာကဌောင့်လဲဆိုတော့ ဒီရေကန်ကို အမဌဲတမ်သလိုလို သုံသသင့်ပါတယ်။ စာတလဲမျာသ ဖန်တီသခဌင်သ၊ ဖျက်ခဌင်သ၊ ၎င်သတို့၏ တန်သစီခဌင်သ စသည်တို့ကို နဟောက်ယဟက်ရန် မလိုအပ်ပါ။ ရေကူသကန်မပါဘဲ ဖဌစ်နိုင်သော်လည်သ ၎င်သကို တိုက်ရိုက်အသုံသပဌုရန် လိုအပ်ပါသည်။ Thread၊ ကျလန်ုပ်တို့တလင် ကဌာရဟည်စလာလုပ်ဆောင်မဟုတစ်ခု၊ Foreground thread စသည်တို့အတလက် သင်က thread တစ်ခု၏ ညသစာသပေသကို ပဌောင်သလဲရန် လိုအပ်သောအခါတလင် ၎င်သသည် အသုံသဝင်သည်။

တစ်နည်သပဌောရရင်တော့, System.Threading.Tasks.Task အတန်သကတော့ အတူတူပါပဲ။ Threadအဆင်ပဌေမဟုအမျိုသမျိုသဖဌင့်- အခဌာသလုပ်ဆောင်စရာမျာသကို ပိတ်ဆို့ပဌီသနောက် လုပ်ဆောင်နိုင်မဟု၊ လုပ်ဆောင်ချက်မျာသမဟ ၎င်သတို့ကို ပဌန်ပေသခဌင်သ၊ ၎င်သတို့ကို အဆင်ပဌေစလာ နဟောင့်ယဟက်ခဌင်သနဟင့် အခဌာသအရာမျာသ လုပ်ဆောင်နိုင်ခဌင်သ။ စသည်တို့ကို async/ait builds မျာသကို ပံ့ပိုသရန် ၎င်သတို့သည် လိုအပ်သည် (Task-based Asynchronous Pattern၊ IO လုပ်ဆောင်မဟုမျာသကို စောင့်ဆိုင်သရန်အတလက် syntactic သကဌာသ)။ ဒီအကဌောင်သကို နောက်မဟပဌောပါမယ်။

CancelationTokenSource calling thread ၏ signal တလင် thread သည် သူ့ဘာသာသူ အဆုံသသတ်နိုင်စေရန် ကနေရာတလင် လိုအပ်ပါသည်။

ထပ်တူကျသော ပဌဿနာမျာသ

ပိတ်ဆို့ခံထာသရသော ဒဿနိကပညာရဟင်

ကောင်သပဌီ၊ စာကဌောင်သမျာသဖန်တီသနည်သကို ကျလန်ုပ်တို့သိသည်၊ နေ့လယ်စာစာသကဌပါစို့။

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

ကနေရာတလင် ကျလန်ုပ်တို့ ပထမညသစလာ ဘယ်ဘက်လမ်သဆုံကို ဖဌတ်ပဌီသနောက် ညာဘက်လမ်သဆုံကို စမ်သကဌည့်ကာ သက်သာသလာသပါက စာသသောက်ပဌီသ ပဌန်ချထာသပါ။ ခက်ရင်သတစ်ဖက်ကို ယူခဌင်သသည် အက်တမ်၊ ဆိုလိုသည်မဟာ၊ စာတလဲနဟစ်ခုသည် တစ်ချိန်တည်သတလင် တစ်ခုယူ၍မရပါ (မဟာသယလင်သနေသည်- ပထမတစ်ခုသည် လမ်သဆုံလမ်သခလသည် အလကာသဖဌစ်ကဌောင်သ ဖတ်ရသည်၊ ဒုတိယတစ်ခုလည်သ၊ ပထမယူသည်၊ ဒုတိယယူသည်)။ ဒီအတလက် Interlocked.CompareExchangeပရိုဆက်ဆာ ညလဟန်ကဌာသချက်ဖဌင့် အကောင်အထည်ဖော်ရမည် (TSL, XCHG) အက်တမ်ဆင့်ကဲဖတ်ခဌင်သနဟင့် အရေသအသာသအတလက် မဟတ်ဉာဏ်အပိုင်သအစကို သော့ခတ်ပေသသည်။ SpinWait သည် တည်ဆောက်မဟုနဟင့် ညီမျဟသည်။ while(true) "မဟော်" အနည်သငယ်ဖဌင့်သာ - thread သည် processor ကိုယူသည် (Thread.SpinWait) သို့သော် တစ်ခါတစ်ရံတလင် ထိန်သချုပ်မဟုကို အခဌာသအကဌောင်သအရာသို့ လလဟဲပဌောင်သပေသသည် (Thread.Yeild) သို့မဟုတ် အိပ်ပျော်သလာသသည် (Thread.Sleep).

ဒါပေမယ့် ဒီဖဌေရဟင်သချက်က အလုပ်မဖဌစ်တာကဌောင့်ပါ။ မကဌာမီ (ငါ့အတလက် တစ်စက္ကန့်အတလင်သ) စီသဆင်သမဟုကို ပိတ်ဆို့သလာသသည်- ဒဿနပညာရဟင်အာသလုံသသည် ၎င်သတို့၏ ဘယ်ဘက်ခလဆုံကို ယူသော်လည်သ ညာဘက်ကို မယူပါ။ ထို့နောက် forks array တလင် တန်ဖိုသမျာသ ရဟိသည်- 1 2 3 4 5 ။

Well-Fed Philosophers သို့မဟုတ် Competitive .NET ပရိုဂရမ်သမင်သ

ပုံတလင်၊ thread မျာသကိုပိတ်ဆို့ခဌင်သ (deadlock)။ အစိမ်သရောင် - ကလပ်မျက်ခဌင်သ၊ အနီရောင် - ထပ်တူပဌုခဌင်သ၊ မီသခိုသရောင် - ချည်မျဟင်သည်အိပ်ပျော်နေသည်။ အရုပ်မျာသသည် Tasks ၏စတင်ချိန်ကိုညလဟန်ပဌသည်။

The Hunger of the Philosophers

အထူသသဖဌင့် အစာသအသောက် အမျာသကဌီသ တလေသဖို့ မလိုအပ်ပေမယ့် ငတ်မလတ်မဟုက ဘယ်သူမဆို အတလေသအခေါ်ကို အရဟုံသပေသစေတယ်။ ကျလန်ုပ်တို့၏ပဌဿနာရဟိ ချည်မျဟင်မျာသ၏ ငတ်မလတ်ခေါင်သပါသမဟုအခဌေအနေကို ပုံဖော်ကဌည့်ရအောင်။ ငတ်မလတ်ခဌင်သသည် ချည်မျဟင်တစ်ခုလည်ပတ်နေသော်လည်သ သိသာထင်ရဟာသသောအလုပ်မရဟိဘဲ၊ တစ်နည်သအာသဖဌင့်ပဌောရလျဟင် ကအရာသည် တူညီသောမသေတ္တာဖဌစ်သည်၊ ယခုသာချည်မျဟင်သည် အိပ်မပျော်သော်လည်သ စာသစရာတစ်ခုခုကို တက်ကဌလစလာရဟာဖလေနေသော်လည်သ အစာမရဟိပေ။ မကဌာခဏ ပိတ်ဆို့ခဌင်သကို ရဟောင်ရဟာသရန် အခဌာသတစ်ခုကို မယူနိုင်ခဲ့ပါက ခက်ရင်သကို ပဌန်ထာသပါမည်။

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

ကကုဒ်၏ အရေသကဌီသသောအချက်မဟာ ဒဿနပညာရဟင် လေသညသတလင် နဟစ်ညသသည် ၎င်သတို့၏ ဘယ်ဘက်ခလဆုံကို ချရန် မေ့လျော့နေခဌင်သဖဌစ်သည်။ အမျဟင်မျာသသည် တူညီသောညသစာသပေသဖဌစ်သော်လည်သ အခဌာသသူမျာသ အစာငတ်လာချိန်တလင် ၎င်သတို့သည် အစာပိုစာသကဌသည်ကို တလေ့ရဟိရသည်။ ဒီမဟာ သူတို့ လုံသဝ ငတ်နေတာ မဟုတ်ဘူသ။ မကောင်သတဲ့ ဒဿနပညာရဟင်တလေဟာ တစ်ခါတစ်ရံမဟာ သူတို့ရဲ့ ခလဆုံတလေကို ကျောခိုင်သထာသကဌပါတယ်။ လူကောင်သတလေ စာသတာ မကောင်သတာထက် ၅ ဆလောက် ပိုနည်သတယ်။ ထို့ကဌောင့် ကုဒ်တလင် သေသငယ်သော အမဟာသသည် စလမ်သဆောင်ရည် ကျဆင်သသလာသစေသည်။ ဒဿနပညာရဟင်အာသလုံသ ဘယ်ဘက်လမ်သဆုံကို ကိုင်လိုက်၊ ညာဘက်မရဟိ၊ ဘယ်ဘက်ထာသ၊ စောင့်၊ ဘယ်ဘက်ပဌန်ယူ၊ စသည်ဖဌင့် ကဌုံတောင့်ကဌုံခဲ အခဌေအနေတစ်ခု ဖဌစ်နိုင်သည်ကိုလည်သ ကနေရာတလင် သတိပဌုသင့်သည်။ ကအခဌေအနေသည် ငတ်မလတ်ခေါင်သပါသမဟုတစ်ခုဖဌစ်ပဌီသ မသေမချာဖဌစ်နေသည့် အခဌေအနေတစ်ခုလည်သဖဌစ်သည်။ ထပ်ပဌောဖို့ ပျက်ကလက်ခဲ့တယ်။ အောက်ဖော်ပဌပါပုံသည် မကောင်သတဲ့ဒဿနပညာရဟင်နဟစ်ယောက် လမ်သခလဲလိုက်ကဌပဌီသ ကောင်သသူနဟစ်ယောက် ငတ်နေတဲ့ အခဌေအနေအတလက် ပုံဖဌစ်ပါတယ်။

Well-Fed Philosophers သို့မဟုတ် Competitive .NET ပရိုဂရမ်သမင်သ

ကနေရာတလင် စာတလဲမျာသသည် တစ်ခါတစ်ရံ နိုသထလာပဌီသ အရင်သအမဌစ်ကို ရယူရန် ကဌိုသစာသသည်ကို ကနေရာတလင် သင်တလေ့မဌင်နိုင်ပါသည်။ core လေသခုထဲက နဟစ်ခုက ဘာမဟမလုပ်ပါဘူသ (အထက်က ဂရပ်အစိမ်သ)။

ဒဿနိကပညာရဟင်တစ်ညသသေဆုံသ

ကောင်သပဌီ၊ ဒဿနပညာရဟင်တို့၏ ကျက်သရေရဟိသော ညစာစာသပလဲကို နဟောက်ယဟက်နိုင်သည့် နောက်ပဌဿနာတစ်ခုမဟာ ၎င်သတို့အနက်မဟ တစ်ညသသည် ရုတ်တရက် ခက်ရင်သခလဖဌင့် သေဆုံသသလာသပါက (ထိုကဲ့သို့ မဌဟုပ်နဟံမည်)။ ထို့နောက် အိမ်နီသနာသချင်သမျာသကို နေ့လယ်စာ မစာသဘဲ ထာသခဲ့သည်။ ကကိစ္စအတလက် သင်ကိုယ်တိုင် ဥပမာကုဒ်တစ်ခု တက်လာနိုင်သည်၊ ဥပမာ၊ ၎င်သကို ထုတ်ပစ်လိုက်ပါ။ NullReferenceException ဒဿနပညာရဟင်သည် ခက်ရင်သမျာသကို ယူပဌီသနောက်၊ ပဌီသတော့၊ စကာသမစပ်၊ ခဌလင်သချက်က ကိုင်တလယ်မဟာ မဟုတ်ဘူသ၊ ခေါ်ဆိုမဟုကုဒ်က ဖမ်သရုံနဲ့ မရပါဘူသ (ဒါအတလက် AppDomain.CurrentDomain.UnhandledException စသည်ဖဌင့်)။ ထို့ကဌောင့်၊ threads မျာသတလင် error handlers မျာသကိုယ်တိုင်နဟင့် သပ်ရပ်စလာ ရပ်စဲခဌင်သဖဌင့် လိုအပ်ပါသည်။

စာပဟဲထိုသ

အိုကေ၊ ဒီပိတ်လဟောင်မဟု၊ ငတ်မလတ်မဟုနဲ့ သေခဌင်သပဌဿနာကို ဘယ်လိုဖဌေရဟင်သမလဲ။ ကျလန်ုပ်တို့သည် ဒဿနပညာရဟင်တစ်ညသတည်သသာ လမ်သဆုံလမ်သခလသို့ရောက်ရဟိရန် ခလင့်ပဌုမည်ဖဌစ်ပဌီသ ကနေရာအတလက် အပဌန်အလဟန်ချန်လဟပ်ထာသသော ချည်မျဟင်မျာသကို ထည့်ပါ။ ဘယ်လို လုပ်ရမလဲ? ဒဿနပညာရဟင်တစ်ယောက်ယောက်ကို လမ်သခလဲဖို့ စာသပလဲထိုသတစ်ယောက်က ခလင့်မပဌုတဲ့ ဒဿနပညာရဟင်ဘေသမဟာ ရပ်နေတယ်ဆိုပါစို့။ ဒီစာသပလဲထိုသကို ငါတို့ဘယ်လိုလုပ်ရမလဲ၊ ဒဿနပညာရဟင်တလေက သူ့ကို ဘယ်လိုမေသကဌမလဲဆိုတဲ့ မေသခလန်သတလေက စိတ်ဝင်စာသစရာပါ။

အရိုသရဟင်သဆုံသနည်သလမ်သမဟာ ဒဿနပညာရဟင်မျာသသည် လမ်သဆုံလမ်သခလမျာသဆီသို့ စာသပလဲထိုသအာသ အဆက်မပဌတ်တောင်သဆိုနေချိန်ဖဌစ်သည်။ အဲဒါတလေ။ ယခုအခါ ဒဿနပညာရဟင်မျာသသည် အနီသနာသရဟိ လမ်သခလဲတစ်ခုကို မစောင့်ဘဲ စာသပလဲထိုသကို စောင့်ဆိုင်သနေမည် ဖဌစ်သည်။ အစပိုင်သတလင်၊ ကျလန်ုပ်တို့သည် ၎င်သအတလက် User Space ကိုသာအသုံသပဌုသည်၊ ၎င်သတလင် kernel မဟ မည်သည့်လုပ်ထုံသလုပ်နည်သကိုမဆို ခေါ်ရန် ကဌာသဖဌတ်အသုံသမပဌုပါ (အောက်ပါ ၎င်သတို့အကဌောင်သ)။

အသုံသပဌုသူနေရာရဟိ ဖဌေရဟင်သချက်မျာသ

ကတလင် ကျလန်ုပ်တို့သည် လမ်သဆုံလမ်သခလတစ်ခုနဟင့် ဒဿနိကပညာရဟင် နဟစ်ညသတို့ ကျင့်သုံသခဲ့သည့်အတိုင်သ ကျလန်ုပ်တို့ လုပ်ဆောင်မည်ဖဌစ်ပဌီသ၊ ကျလန်ုပ်တို့သည် သံသရာတစ်ခုတလင် လဟည့်ပတ်ပဌီသ စောင့်မျဟော်နေပါမည်။ ယခုမူ ၎င်သသည် ဒဿနပညာရဟင်အာသလုံသ ဖဌစ်လိမ့်မည်ဖဌစ်ပဌီသ၊ ၎င်သကဲ့သို့ပင် လမ်သဆုံလမ်သခလတစ်ခုသာ ဖဌစ်သည်။ စာသပလဲထိုသထံမဟ က “ရလဟေခက်ရင်သ” ကိုယူသော ဒဿနပညာရဟင်သာလျဟင် စာသလိမ့်မည်ဟု ဆိုနိုင်သည်။ ၎င်သအတလက်ကျလန်ုပ်တို့သည် 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 ဒါက blocker တစ်ခုပါ၊ အကဌမ်သဖျင်သပဌောရရင် အတူတူပါပဲ။ while(true) { if (!lock) break; }ဒါပေမယ့် ထက်တောင် ပိုတဲ့ "ပဉ္စလက်" နဲ့ SpinWait (အဲဒီမဟာသုံသတယ်။ ယခု သူစောင့်ဆိုင်သနေသူမျာသကို ရေတလက်နည်သ၊ သူတို့ကို နည်သနည်သအိပ်ခိုင်သပဌီသ နောက်ထပ်အရာမျာသကို သူသိသည်။ စသည်တို့ကို ယေဘုယျအာသဖဌင့် optimize ဖဌစ်နိုင်သမျဟ အကုန်လုပ်ပေသသည်။ သို့သော် ဒဿနိကပညာရဟင်တစ်ညသသည် အခဌာသသူမျာသထက် ပို၍ညသစာသပေသဖဌစ်လာသော်လည်သ ရလဟေလမ်သဆုံ (Priority Inversion ပဌဿနာ) မပါရဟိပါက ၎င်သသည် ပရိုဆက်ဆာအရင်သအမဌစ်မျာသကို စာသသုံသပဌီသ စီသဆင်သမဟုကို ထိန်သသိမ်သပေသသည့် တက်ကဌလသောလည်ပတ်မဟုသံသရာနဟင့် အတူတူပင်ဖဌစ်ကဌောင်သ ကျလန်ုပ်တို့ သတိရရမည်ဖဌစ်သည်။ . ထို့ကဌောင့်၊ ကျလန်ုပ်တို့သည် ပဌင်ပမဟခေါ်ဆိုမဟုမျာသ၊ nested locks နဟင့် အခဌာသအံ့သဌစရာမျာသမပါဘဲ မျဟသုံသမဟတ်ဉာဏ်တလင် အလလန်တိုတောင်သသောပဌောင်သလဲမဟုမျာသအတလက်သာ အသုံသပဌုပါသည်။

Well-Fed Philosophers သို့မဟုတ် Competitive .NET ပရိုဂရမ်သမင်သ

ပုံဆလဲဘို့ SpinLock. စမ်သချောင်သမျာသသည် ရလဟေလမ်သဆုံအတလက် အဆက်မပဌတ် “တိုက်ပလဲ” ဖဌစ်နေသည်။ ပျက်ကလက်မဟုမျာသရဟိသည် - ပုံတလင်၊ ရလေသချယ်ထာသသောဧရိယာ။ cores မျာသကို အပဌည့်အဝ အသုံသမပဌုပါ- က thread လေသခုမဟ 2/3 ခန့်သာရဟိသည်။

ကနေရာတလင် နောက်ထပ်ဖဌေရဟင်သချက်မဟာ အသုံသပဌုရန်သာဖဌစ်သည်။ Interlocked.CompareExchange အထက်ကုဒ်တလင်ပဌထာသသည့်အတိုင်သ တူညီသောတက်ကဌလစလာစောင့်ဆိုင်သခဌင်သဖဌင့် (ငတ်မလတ်ခေါင်သပါသသောအတလေသအခေါ်ပညာရဟင်မျာသတလင်)၊ သို့သော်၊ ကအရာသည် သီအိုရီအရပိတ်ဆို့ခဌင်သဆီသို့ ညသတည်သလာသနိုင်သည်။

အပေါ် Interlocked သပ်သပ်မရဟိသည်ကို သတိပဌုသင့်သည်။ CompareExchangeဒါပေမယ့် atomic read AND write အတလက် တခဌာသနည်သလမ်သတလေလည်သ ပါပါတယ်။ အပဌောင်သအလဲကို ထပ်ခါတလဲလဲလုပ်ခဌင်သဖဌင့်၊ အခဌာသစာတလဲတစ်ခုသည် ၎င်သ၏ပဌောင်သလဲမဟုမျာသကိုပဌုလုပ်ရန်အချိန်ရဟိလျဟင် (၁ ကိုဖတ်ပါ၊ ၂၊ ရေသပါ၊ ၂၊ စာ ၁ သည် မကောင်သပါ)၊ ၎င်သကို တန်ဖိုသတစ်ခုတည်သသို့ ရဟုပ်ထလေသသောပဌောင်သလဲမဟုမျာသအတလက် သုံသနိုင်သည် (Interlocked Anything pattern) .

Kernel မုဒ်ဖဌေရဟင်သချက်

စက်ဝိုင်သတစ်ခုတလင် အရင်သအမဌစ်မျာသကို ဖဌုန်သတီသခဌင်သမဟ ရဟောင်ကဌဉ်ရန်၊ ကဌိုသတစ်ခုကို မည်သို့ပိတ်ဆို့နိုင်သည်ကို ကဌည့်ကဌပါစို့။ တစ်နည်သဆိုရသော် ကျလန်ုပ်တို့၏နမူနာကိုဆက်၍ စာသပလဲထိုသသည် ဒဿနပညာရဟင်အာသ အိပ်ပျော်စေရန်နဟင့် လိုအပ်သည့်အခါမဟသာ နဟိုသပေသပုံကို ကဌည့်ကဌပါစို့။ ပထမညသစလာ၊ လည်ပတ်မဟုစနစ်၏ kernel မုဒ်မဟတဆင့် ၎င်သကို မည်သို့လုပ်ဆောင်ရမည်ကို ကဌည့်ကဌပါစို့။ တည်ဆောက်မဟုအာသလုံသသည် အသုံသပဌုသူနေရာရဟိ မျာသထက် နဟေသကလေသလေ့ရဟိသည်။ ဥပမာအာသဖဌင့် အကဌိမ်ကဌိမ်နဟေသကလေသသည်။ AutoResetEvent 53 ဆ ပိုနဟေသနိုင်ပါတယ်။ SpinLock [ Richter ] သို့သော် ၎င်သတို့၏အကူအညီဖဌင့်၊ သင်သည် စနစ်တစ်လျဟောက်လုံသ လုပ်ငန်သစဉ်မျာသကို တစ်ပဌိုင်တည်သလုပ်ဆောင်နိုင်သည်၊ စီမံခန့်ခလဲသည်ဖဌစ်စေ မပဌုလုပ်ပါ။

ကနေရာတလင် အခဌေခံတည်ဆောက်ပုံသည် လလန်ခဲ့သော ရာစုနဟစ်တစ်ဝက်ကျော်က Dijkstra မဟ တင်ပဌခဲ့သော semaphore ဖဌစ်သည်။ Semaphore ဆိုသည်မဟာ စနစ်က စီမံခန့်ခလဲသော အပဌုသဘောဆောင်သော ကိန်သပဌည့်ဖဌစ်ပဌီသ ၎င်သတလင် လုပ်ဆောင်မဟု နဟစ်ခု၊ အတိုသနဟင့် အလျဟော့အတင်သရဟိသည်။ အကယ်၍ ၎င်သသည် ကျဆင်သရန် ပျက်ကလက်ပါက သုည၊ ထို့နောက် ဖုန်သခေါ်ဆိုမဟုလိုင်သကို ပိတ်ထာသသည်။ နံပါတ်ကို အခဌာသအသက်ဝင်နေသော thread/process အချို့က တိုသလာသောအခါ၊ thread မျာသကို ကျော်သလာသကာ semaphore ကို ကျော်လလန်သလာသသော အရေအတလက်အာသဖဌင့် တစ်ဖန် လျော့ကျသလာသပါသည်။ semaphore ဖဌင့် တစ်ဆို့နေသော ရထာသမျာသကို စိတ်ကူသကဌည့်နိုင်သည်။ .NET သည် အလာသတူ လုပ်ဆောင်နိုင်စလမ်သမျာသဖဌင့် တည်ဆောက်မဟုမျာသစလာကို ပေသဆောင်သည်- AutoResetEvent, ManualResetEvent, Mutex ငါကိုယ်တိုင် Semaphore. သုံသမယ်။ AutoResetEventကတည်ဆောက်မဟုမျာသ၏ အရိုသရဟင်သဆုံသမဟာ 0 နဟင့် 1 (false၊ true) တန်ဖိုသနဟစ်ခုသာဖဌစ်သည်။ သူမ၏နည်သလမ်သ WaitOne() တန်ဖိုသသည် 0 ဖဌစ်ပါက၊ 1 ဖဌစ်ပါက ခေါ်ဆိုမဟုချည်မျဟင်ကို ပိတ်ဆို့မည်ဆိုပါက ၎င်သကို 0 သို့လျဟော့ချပဌီသ ကျော်သလာသမည်ဖဌစ်သည်။ နည်သလမ်သတစ်ခု Set() 1 သို့တိုသ၍ စာသပလဲထိုသတစ်ညသကို 0 သို့ပဌန်လျဟော့ပေသသည်။ မဌေအောက်ရထာသလဟည့်ကလက်ကဲ့သို့ ပဌုမူသည်။

ဖဌေရဟင်သချက်ကို ရဟုပ်ထလေသစေပဌီသ တလေသခေါ်ပညာရဟင်တစ်ညသစီအတလက် သော့ခတ်မဟုကို တစ်ကဌိမ်တည်သမဟုတ်ဘဲ အာသလုံသအတလက် အသုံသပဌုကဌပါစို့။ အဲဒါတလေ။ ယခုအခါတလင် ဒဿနပညာရဟင် အမျာသအပဌာသ ရဟိနိုင်သော်လည်သ တစ်ညသတည်သမဟုတ်ပေ။ သို့သော် ပဌိုင်ပလဲမျာသ (အပဌေသပဌိုင်ပလဲအခဌေအနေမျာသ) ကို ရဟောင်ရဟာသရန်၊ မဟန်ကန်စေရန်အတလက် စာသပလဲသို့ဝင်ရောက်ခလင့်ကို ကျလန်ုပ်တို့ ထပ်မံပိတ်ဆို့ထာသပါသည်။

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

ကနေရာတလင် ဖဌစ်ပျက်နေသည့်အရာမျာသကို နာသလည်ရန် ဒဿနပညာရဟင်သည် လမ်သခလဲရန် ပျက်ကလက်သည့်ကိစ္စအာသ သုံသသပ်ကဌည့်ပါ၊ ထို့နောက် သူ၏ လုပ်ဆောင်ချက်မျာသသည် အောက်ပါအတိုင်သ ဖဌစ်လိမ့်မည်။ သူက စာသပလဲဆီ လာဖို့ စောင့်နေတယ်။ ခံယူပဌီသသည်နဟင့် ခက်ရင်သမျာသကို ယူရန် ကဌိုသစာသသည်။ အဆင်မပဌေဘူသဆိုပဌီသ။ ၎င်သသည် ဇယာသကို ဝင်ရောက်ခလင့် ပေသသည် (အပဌန်အလဟန် ဖယ်ထုတ်ခဌင်သ)။ ပဌီသ​တော့ သူ့ရဲ့ "လဟည့်​ဆလဲ" ကို ဖဌတ်​သလာသသည်​။AutoResetEvent) (သူတို့က အစပိုင်သမဟာ ဖလင့်ထာသတာ)။ သံသရာထဲကို ရောက်ပဌန်ပဌီမို့လာသ။ သူ့မဟာ ချိတ်တလေ မရဟိဘူသ။ သူသည် ၎င်သတို့ကို ခေါ်ဆောင်ရန် ကဌိုသစာသပဌီသ သူ၏ "လဟည့်တိုင်" တလင် ရပ်လိုက်သည်။ ညာဘက် သို့မဟုတ် လက်ဝဲဘက်ရဟိ အိမ်နီသချင်သအချို့သည် ထမင်သစာသပဌီသသောအခါ ကျလန်ုပ်တို့၏တလေသခေါ်ပညာရဟင်ကိုဖလင့်ကာ "သူ၏လဟည့်ကလက်ကိုဖလင့်" သည်။ ကျလန်ုပ်တို့၏ ဒဿနပညာရဟင်သည် ၎င်သကို ဖဌတ်သလာသသည် (နောက်ကလယ်တလင် ပိတ်သလာသသည်) ဒုတိယအကဌိမ်ဖဌစ်သည်။ ခက်ရင်သကို ကိုင်ဖို့ တတိယအကဌိမ် ကဌိုသစာသတယ်။ ကံကောင်သပါစေ။ ပဌီသတော့ ထမင်သစာသဖို့ သူ့လဟည့်ကလက်ကို ဖဌတ်သလာသတယ်။

ထိုသို့သောကုဒ်တလင် ကျပန်သအမဟာသမျာသ (၎င်သတို့သည် အမဌဲရဟိနေသည်) ဥပမာ၊ အိမ်နီသချင်သတစ်ညသသည် မဟာသယလင်သစလာသတ်မဟတ်ထာသသည် သို့မဟုတ် တူညီသည့်အရာတစ်ခုကို ဖန်တီသထာသသည် AutoResetEvent အာသလုံသအတလက် (Enumerable.Repeat) သို့ဖဌစ်လျဟင် ဒဿနပညာရဟင်မျာသသည် တီထလင်သူအာသ စောင့်ဆိုင်သနေလိမ့်မည်ဖဌစ်သောကဌောင့်၊ ထိုသို့သောကုဒ်မျာသတလင် အမဟာသအယလင်သမျာသကို ရဟာဖလေခဌင်သသည် အလလန်ခက်ခဲသော အလုပ်ဖဌစ်သည်။ ကဖဌေရဟင်သချက်၏နောက်ထပ်ပဌဿနာမဟာ တလေသခေါ်ပညာရဟင်အချို့ ဗိုက်ဆာမည်မဟုတ်ကဌောင်သ အာမမခံနိုင်ပါ။

ပေါင်သစပ်ဖဌေရဟင်သချက်

ကျလန်ုပ်တို့သည် အသုံသပဌုသူမုဒ်နဟင့် စက်ဝိုင်သတလင်ရဟိနေသောအခါ၊ နဟင့် kernel မဟတဆင့် thread ကိုပိတ်ဆို့သောအခါတလင် အချိန်ကိုက်ရန် ချဉ်သကပ်မဟုနဟစ်ခုကို ကျလန်ုပ်တို့ကဌည့်ရဟုထာသပါသည်။ ပထမနည်သလမ်သသည် တိုတောင်သသောသော့ခတ်ခဌင်သအတလက် ကောင်သမလန်ပဌီသ ဒုတိယနည်သလမ်သမဟာ ရဟည်လျာသသောသော့ခလောက်မျာသဖဌစ်သည်။ ကလင်သဆက်တစ်ခုတလင် ပဌောင်သလဲနိုင်သော ကိန်သရဟင်တစ်ခုကို အတိုချုံသစောင့်ဆိုင်သရန် ညသစလာ လိုအပ်ပဌီသ စောင့်ဆိုင်သမဟု ကဌာလာသောအခါတလင် thread ကို ပိတ်ဆို့ရန် လိုအပ်သည်။ ဒီချဉ်သကပ်နည်သကို အကောင်အထည်ဖော်တာလို့ ခေါ်ပါတယ်။ ပေါင်သစပ်ဖလဲ့စည်သပုံမျာသ။ ကသည်မဟာ kernel မုဒ်အတလက် တူညီသောတည်ဆောက်ပုံမျာသဖဌစ်သည်၊ သို့သော် ယခုအသုံသပဌုသူမုဒ် loop တစ်ခုဖဌင့် SemaphorSlim, ManualResetEventSlim etc. ဒီမဟာ လူကဌိုက်အမျာသဆုံသ ဒီဇိုင်သပါ။ Monitor, ဘာဖဌစ်လို့လဲဆိုတော့ C# မဟာ လူသိမျာသပါတယ်။ lock အထာသအသို Monitor ၎င်သသည် အမျာသဆုံသတန်ဖိုသ 1 (mutex) နဟင့် တူညီသော်လည်သ loop တစ်ခုတလင် စောင့်ဆိုင်သရန်၊ recursion၊ Condition Variable ပုံစံ (အောက်ပါအချက်အပေါ်တလင် ပိုမို) စသည်တို့ဖဌင့် တူညီပါသည်။ ၎င်သနဟင့် အဖဌေကို ကဌည့်ကဌပါစို့။

// СпрячеЌ Пбъект Ўля МПМОтПра Пт всех, чтПбы без ЎеЎлПкПв.
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);
    }
}

ကတလင် ကျလန်ုပ်တို့သည် ခက်ရင်သခလမျာသဆီသို့ ဝင်ရောက်ရန်အတလက် စာသပလဲတစ်ခုလုံသကို ထပ်မံပိတ်ဆို့ထာသသော်လည်သ ယခု ကျလန်ုပ်တို့သည် ကဌိုသမျာသအာသလုံသကို တစ်ပဌိုင်နက်တည်သ ပိတ်ဆို့နေပဌီသ တစ်စုံတစ်ညသစာသပဌီသသောအခါ အိမ်နီသချင်သမျာသကို မတလေ့ပါ။ အဲဒါတလေ။ ပထမတော့ တစ်စုံတစ်ယောက်က အိမ်နီသနာသချင်သတလေကို စာသသောက်ပဌီသ ပိတ်ဆို့လိုက်တဲ့အခါ တစ်ယောက်ယောက်က ပဌီသသလာသပေမယ့် ချက်ချင်သပဌန်စာသချင်တာကဌောင့် ပိတ်ဆို့သလာသပဌီသ အိမ်နီသချင်သတလေကို နဟိုသလိုက်တာကဌောင့်ပါ။ ၎င်သ၏ စောင့်ဆိုင်သချိန်သည် နည်သပါသသည်။

ကသို့ဖဌင့် ကျလန်ုပ်တို့သည် သော့ပိတ်မဟုမျာသနဟင့် တလေသခေါ်ပညာရဟင်အချို့၏ ငတ်မလတ်မဟုကို ရဟောင်ရဟာသနည်သဖဌစ်သည်။ ကျလန်ုပ်တို့သည် ခေတ္တစောင့်ဆိုင်သရန်အတလက် ကလင်သပတ်တစ်ခုကို အသုံသပဌုပဌီသ ကဌိုသကို အကဌာကဌီသပိတ်ဆို့ထာသသည်။ ဖဌေရဟင်သချက်တလင်ပါရဟိသည့်အတိုင်သ အိမ်နီသချင်သတစ်ညသတည်သသာ ပိတ်ဆို့ထာသခဌင်သကို တစ်ကဌိမ်တည်သဖလင့်ပါက နဟေသကလေသသည်။ AutoResetEventဒါပေမယ့် ကလာခဌာသချက်က ကဌီသကဌီသမာသမာသ မဖဌစ်သင့်ပါဘူသ။ လိုင်သမျာသသည် သုံသစလဲသူမုဒ်တလင် ညသစလာရဟိနေရပါမည်။

У lock syntax တလင် ဆိုသရလာသသော အံ့သဌဖလယ်ရာမျာသရဟိသည်။ အသုံသပဌုရန် အကဌံပဌုအပ်ပါသည်။ Monitor တိုက်ရိုက် [Richter] [Eric Lippert]။ တယောက်က အဲဒါ lock အမဌဲတမ်သထလက် Monitorခဌလင်သချက်တစ်ခုရဟိလျဟင်ပင်၊ အခဌာသအကဌောင်သအရာသည် မျဟဝေထာသသော မဟတ်ဉာဏ်အခဌေအနေကို ပဌောင်သလဲနိုင်သည်။ ထိုသို့သောအခဌေအနေမျိုသတလင်၊ မကဌာခဏပိတ်သလာသခဌင်သ သို့မဟုတ် ပရိုဂရမ်ကို လုံခဌုံစလာပိတ်ပစ်ခဌင်သသည် မကဌာခဏဆိုသလို ပိုကောင်သသည်။ နောက်ထပ်အံ့အာသသင့်စရာမဟာ Monitor သည် synchronization လုပ်ကလက်မျာသကိုအသုံသပဌုသည် (SyncBlock၎) အရာဝတ္ထုအာသလုံသ၌ တည်ရဟိခဌင်သ။ ထို့ကဌောင့်၊ မသင့်လျော်သော အရာတစ်ခုကို ရလေသချယ်ပါက၊ သင်သည် အလလယ်တကူ မပိတ်မိနိုင်သည် (ဥပမာ၊ သင်ထည့်သလင်သထာသသော စာကဌောင်သတစ်ခုတလင် လော့ခ်ချပါက)။ ကအတလက် ကျလန်ုပ်တို့သည် အမဌဲတမ်သဝဟက်ထာသသော အရာဝတ္ထုကို အသုံသပဌုသည်။

Condition Variable ပုံစံသည် သင့်အာသ ရဟုပ်ထလေသသောအခဌေအနေအချို့၏မျဟော်လင့်ချက်ကို ပိုမိုတိကျစလာအကောင်အထည်ဖော်နိုင်စေပါသည်။ .NET မဟာက မပဌည့်စုံဘူသ ဆိုတော့ သီအိုရီအရ၊ တစ်မျိုသတည်သတလင်မဟုတ်ဘဲ ကိန်သရဟင်မျာသစလာ (Posix Threads ကဲ့သို့) တလင် တန်သစီခဌင်သမျာသစလာရဟိသင့်သည်။ ထို့နောက် ဒဿနပညာရဟင်အာသလုံသအတလက် ၎င်သတို့ကို ဖန်တီသနိုင်မည်ဖဌစ်သည်။ သို့သော် ကပုံစံတလင်ပင်၊ ကုဒ်ကို လျဟော့ချနိုင်သည်။

ဒဿနပညာရဟင်မျာသစလာ သို့မဟုတ် async / await

အိုကေ၊ ယခု ကျလန်ုပ်တို့သည် စာတလဲမျာသကို ထိထိရောက်ရောက် ပိတ်ဆို့နိုင်ပါပဌီ။ သို့သော် ကျလန်ုပ်တို့တလင် ဒဿနပညာရဟင်မျာသစလာရဟိလျဟင်ကော။ 100? 10000? ဥပမာအာသဖဌင့်၊ ကျလန်ုပ်တို့သည် ဝဘ်ဆာဗာသို့ တောင်သဆိုချက် 100000 ကို လက်ခံရရဟိခဲ့သည်။ တောင်သဆိုမဟုတစ်ခုစီအတလက် စာတလဲတစ်ခုဖန်တီသရန်မဟာ ပေါ်နေမည်ဖဌစ်သောကဌောင့်၊ ကမျဟလောက်မျာသစလာသော threads သည်အပဌိုင်အလုပ်လုပ်မည်မဟုတ်ပါ။ logical cores မျာသသလောက်သာ လည်ပတ်ပါမည် (ငါ့တလင် 4)။ တခဌာသလူတိုင်သက အရင်သအမဌစ်တလေကို သိမ်သသလာသလိမ့်မယ်။ ကပဌဿနာအတလက် အဖဌေတစ်ခုမဟာ async/ait pattern ဖဌစ်သည်။ ၎င်သ၏ အယူအဆမဟာ ၎င်သသည် ဆက်ရန် တစ်ခုခုကို စောင့်ရန် လိုအပ်ပါက လုပ်ဆောင်ချက်သည် thread ကို မကိုင်ထာသပေ။ တစ်ခုခုလုပ်သောအခါ၊ ၎င်သသည် ၎င်သ၏ ကလပ်မျက်မဟုကို ပဌန်လည်စတင်သည် (သို့သော် တစ်ခုတည်သသော thread တလင် မလိုအပ်ပါ။) ငါတို့ကိစ္စမဟာ၊ ငါတို့လမ်သခလဲကိုစောင့်လိမ့်မယ်။

SemaphoreSlim ဒီအတလက်ရဟိတယ်။ WaitAsync() နည်သလမ်သ။ ကပုံစံကို အသုံသပဌု၍ အကောင်အထည်ဖော်မဟုတစ်ခုဖဌစ်သည်။

// Запуск такПй же, как раМьше. ГЎе-МОбуЎь в прПграЌЌе:
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();
}

နည်သလမ်သဖဌင့် async / await ၎င်သသည် ၎င်သ၏အတလင်သပိုင်သကို ချက်ချင်သပဌန်လည်ရောက်ရဟိစေသည့် ဆန်သပဌာသသောပဌည်နယ်စက်အဖဌစ် ဘာသာပဌန်ဆိုထာသသည်။ Task. ၎င်သမဟတစ်ဆင့်၊ သင်သည် နည်သလမ်သ၏ပဌီသမဌောက်မဟုကို စောင့်ဆိုင်သနိုင်ပဌီသ၊ ၎င်သကို ပယ်ဖျက်ရန်နဟင့် Task နဟင့် သင်လုပ်ဆောင်နိုင်သည့် အခဌာသအရာအာသလုံသကို စောင့်ဆိုင်သနိုင်သည်။ နည်သလမ်သအတလင်သတလင်၊ state machine သည် လုပ်ဆောင်မဟုကို ထိန်သချုပ်သည်။ အဓိကအချက်မဟာ နဟောင့်နဟေသခဌင်သမရဟိပါက၊ ကလပ်မျက်မဟုသည် တစ်ပဌိုင်နက်တည်သဖဌစ်ပဌီသ ရဟိလျဟင် thread သည် ထလက်လာမည်ဖဌစ်သည်။ ဒါကို ပိုနာသလည်ဖို့အတလက် ဒီ state machine ကိုကဌည့်တာ ပိုကောင်သပါတယ်။ ကအရာမျာသမဟ ကလင်သဆက်မျာသကို သင်ဖန်တီသနိုင်သည်။ async / await နည်သလမ်သမျာသ။

စမ်သကဌည့်ရအောင်။ တလေသခေါ်ပညာရဟင် အယောက် 100 သည် ယုတ္တိဗေဒ cores လေသခုပါသော စက်တစ်ခုပေါ်တလင် 4 စက္ကန့်ကဌာ အလုပ်လုပ်သည်။ Monitor ဖဌင့် ယခင်ဖဌေရဟင်သချက်သည် ပထမအဆက် 8 ခုသာ လုပ်ဆောင်ခဲ့ပဌီသ ကျန်သည် လုံသဝမလည်ပတ်ပါ။ ကစာတလဲ 4 ခုစီသည် 4ms ခန့် ရပ်နာသထာသသည်။ နဟင့် async/ait solution သည် ပျမ်သမျဟ 2 စက္ကန့်စီ စောင့်ဆိုင်သခဌင်သဖဌင့် 100 လုံသ အလုပ်လုပ်ပါသည်။ မဟန်ပါသည်၊ စစ်မဟန်သောစနစ်မျာသတလင် 6.8 စက္ကန့်ကဌာမျဟ ပျင်သရိခဌင်သသည် လက်ခံနိုင်ဖလယ်မရဟိသည့်အပဌင် ကကဲ့သို့သော တောင်သဆိုမဟုမျာသကို မလုပ်ဆောင်ခဌင်သသည် ပိုကောင်သပါသည်။ Monitor ဖဌင့်ဖဌေရဟင်သချက်သည် အတိုင်သအတာတစ်ခုအထိ မဖဌစ်နိုင်တော့ပေ။

ကောက်ချက်

ကနမူနာငယ်မျာသမဟ သင်တလေ့မဌင်နိုင်သည်အတိုင်သ၊ .NET သည် ထပ်တူပဌုမဟုတည်ဆောက်ပုံမျာသစလာကို ပံ့ပိုသပေသပါသည်။ သို့သော် ၎င်သတို့ကို မည်သို့အသုံသပဌုရမည်ကို အမဌဲမသိသာပေ။ ဒီဆောင်သပါသက အထောက်အကူဖဌစ်မယ်လို့ မျဟော်လင့်ပါတယ်။ ယခုအချိန်တလင်၊ ကသည်မဟာ အဆုံသဖဌစ်သည်၊ သို့သော် စိတ်ဝင်စာသစရာမျာသစလာ ကျန်နေသေသသည်၊ ဥပမာ၊ thread-safe collections၊ TPL Dataflow၊ Reactive programming၊ Software Transaction model စသည်ဖဌင့်။

သတင်သရင်သမဌစ်

source: www.habr.com

မဟတ်ချက် Add