Sobes.tech
Junior

Ինչ է deadlock-ը?

sobes.tech AI

Պատասխան AI-ից

Դեդլոկը՝ դա մուտքի փակուղի է բազմասխալային ծրագրավորման մեջ, երբ երկու կամ ավելի թելեր միմյանց խոչընդոտում են, սպասելով ռեսուրսների, որոնք զբաղված են մյուս թելերով նույն խմբում:

Դեդլոկի առաջացման պայմանները (Կոֆման պայմաններ)

  1. փոխադարձ բացառություն (Mutual Exclusion): ռեսուրսները չեն կարող օգտագործվել միաժամանակ մի քանի թելերով:
  2. պահում և սպասում (Hold and Wait): արդեն մի ռեսուրս ունեցող թելերը սպասում են լրացուցիչ ռեսուրսի, որը զբաղեցված է այլ թելով:
  3. առանց նախապայման (No Preemption): ռեսուրսը չի կարող ուժեղ կերպով վերցվել այն թելից, որը նրան տիրապետում է; այն կարող է ազատվել միայն ինքնուրույն թելով:
  4. շրջանաձև սպասում (Circular Wait): գոյություն ունի երկու կամ ավելի թելերի շղթա, որտեղ յուրաքանչյուր թել սպասում է ռեսուրսի, որը տիրապետում է հաջորդ թելին շղթայում:

Պարզ օրինակ դեդլոկի:

երկու թել, երկու ռեսուրս (A և B):

  • Թել 1-ը գրավում է ռեսուրս A-ն:
  • Թել 2-ը գրավում է ռեսուրս B-ն:
  • Թել 1-ը փորձում է գրավել ռեսուրս B-ն (որը զբաղեցված է Թել 2-ի կողմից):
  • Թել 2-ը փորձում է գրավել ռեսուրս A-ն (որը զբաղեցված է Թել 1-ի կողմից):

Երկուսն էլ թելերը հավերժորեն փակված են:

// Պարզ օրինակ դեդլոկի սիմուլյացիայի lock օգտագործելով
object resourceA = new object();
object resourceB = new object();

void Thread1Method()
{
    lock (resourceA) // Թել 1-ը գրավում է A-ն
    {
        Console.WriteLine("Թել 1-ը գրավեց ռեսուրս A");
        Thread.Sleep(100); // Փոքր դադարեցում՝ թելերի փոխարկման ցուցադրության համար
        lock (resourceB) // Թել 1-ը փորձում է գրավել B-ն
        {
            Console.WriteLine("Թել 1-ը գրավեց ռեսուրս B");
        }
    }
}

void Thread2Method()
{
    lock (resourceB) // Թել 2-ը գրավում է B-ն
    {
        Console.WriteLine("Թել 2-ը գրավեց ռեսուրս B");
        Thread.Sleep(100); // Փոքր դադար
        lock (resourceA) // Թել 2-ը փորձում է գրավել A-ն
        {
            Console.WriteLine("Թել 2-ը գրավեց ռեսուրս A");
        }
    }
}

// Թելերի ստեղծում և գործարկում կարող է հանգեցնել դեդլոկի:
// new Thread(Thread1Method).Start();
// new Thread(Thread2Method).Start();

// Այս կոդի գործարկումը կարող է, բայց չի պարտադիր, ցույց տալ դեդլոկ, քանի որ կատարման կարգը կախված է պլանավորիչից:
// Եթե Թել 1-ը գրավի A-ն, իսկ Թել 2-ը՝ B-ն, նախքան առաջինը գրավի B-ն, տեղի կունենա դեդլոկ:

Դեդլոկների կանխարգելումը հաճախ հասնում է՝

  • ռեսուրսների գրավման կարգը կարգավորելով (միշտ նույն կարգով գրավել ռեսուրսները):
  • օգտագործելով ժամանակային սահմանափակ գրավման մեթոդներ (փորձել ռեսուրս գրավել որոշ ժամանակում):
  • նախագծելով առանց միաժամանակ մի քանի բլոկավորումների պահելու անհրաժեշտության:
  • օգտագործելով ագրեգատային օպերացիաներ կամ բարձր մակարդակի սինխրոնիզացիայի primitives (օրինակ, Monitor.TryEnter, ReaderWriterLockSlim):

Դեդլոկները դժվար է հայտնաբերել, քանի որ դրանք կախված են թելերի կատարման կարգից և հաճախ հայտնվում են միայն բեռի տակ: Visual Studio-ն տրամադրում է գործիքներ դրանց հայտնաբերման և վերլուծության համար: