Sobes.tech
Middle+

Ի՞նչ է ամենաուշագրավ օրինակն of deadlock in iOS, որը կարող եք բերել։

sobes.tech AI

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

Իմաստուն օրինակ է iOS-ում deadlock-ի, երբ փորձում ենք UI-ն թաքնված հոսքից թարմացնել հատուկ մեխանիզմների օգտագործումից բացի:

// Այս կոդը կհանգեցնի deadlock կամ կոտրվելու (կախված iOS-ի տարբերակից և կոնտեքստից)
// երբ կանչվում է գլխավոր հոսքից դուրս
DispatchQueue.global().async {
    // Կատարում ենք որոշ ֆոնային աշխատանք...
    print("Ֆոնային աշխատանքը կատարվում է")

    // Փորձում ենք ուղղակիորեն թարմացնել UI-ն ֆոնային հոսքից
    // Դա կհանգեցնի արտահայտության կամ deadlock-ի, քանի որ UIKit-ը չի ապահովում հոսքային անվտանգություն
    DispatchQueue.main.syncが必要です!
    // Սա ավելացվել է խնդրի ցուցադրման համար - իրական կոդում այդպես անել չի կարելի!
    DispatchQueue.main.sync {
        // Փորձում ենք թարմացնել նշանը գլխավոր հոսքում
        // Բայց քանի որ մենք արդեն սինխրոն սպասում ենք գլխավոր հոսքին, որը բլոկավորված է
        // մեր սեփական սինխրոն ուղարկման բլոկով, առաջանում է deadlock:
        print("Փորձում ենք թարմացնել UI-ն")
        // someLabel.text = "Թարմացվել է ֆոնից" // Օրինակ տող, որը կարող է խնդիր առաջացնել
    }
    print("Ֆոնային աշխատանքը ավարտվեց")
}

Նկարագրություն:

UIKit (ֆրեյմվորկ՝ օգտագործողի ինտերֆեյսի կառուցման համար iOS-ում) չի ապահովում հոսքային անվտանգություն: Բոլոր UI-ով կապված գործողությունները պետք է կատարվեն միայն գլխավոր հոսքում (main thread):

Նշված օրինակով, եթե կանչեք DispatchQueue.main.sync { ... } բլոկը ֆոնային հոսքից, ապա:

  1. Ֆոնային հոսքը կբլոկավորվի և կսպասի, մինչև գլխավոր հոսքը կատարի ուղարկված բլոկը:
  2. Գլխավոր հոսքը կարող է այդ ժամանակ զբաղված լինել կամ, ավելի հավանական է, սպասում է ինչ-որ գործողության ավարտին, որը պետք է սկսվեր ֆոնային հոսքից (ինչը այս կոնկրետ օրինակով չի, բայց սինխրոն ուղարկումը գլխավոր հոսք՝ ֆոնային հոսքից արդեն խնդիր է):
  3. sync-ի դեպքում, ֆոնային հոսքը չի կարող ավարտել, մինչև գլխավոր հոսքը չի կատարում ուղարկված բլոկը: Եթե գլխավոր հոսքը արդեն բլոկավորված է (օրինակ, սպասում է ֆոնային հոսքից գործողության ավարտին, որը, իր հերթին, սպասում է գլխավոր հոսքին, կամ պարզապես զբաղված է), առաջանում է ցիկլային սպասում՝ deadlock:

Սխալ լուծում:

Օգտագործել անսինխրոն ուղարկում գլխավոր հոսքին UI թարմացնելու համար:

// Ճիշտ լուծում՝ UI-ն թարմացնել անսինխրոն կերպով գլխավոր հոսքում
DispatchQueue.global().async {
    // Կատարում ենք որոշ ֆոնային աշխատանք...
    print("Ֆոնային աշխատանքը կատարվում է")

    // Ուղարկում ենք UI-ի թարմացումը անսինխրոն գլխավոր հոսքին
    DispatchQueue.main.async {
        print("Թարմացնում ենք UI-ն գլխավոր հոսքում")
        // someLabel.text = "Թարմացվել է ֆոնից" // Ճիշտ տեղը UI-ն թարմացնելու համար
    }
    print("Ֆոնային աշխատանքը ավարտվեց")
}

Այստեղ ֆոնային հոսքը չի բլոկավորվում բլոկի ուղարկման ժամանակ, ինչը թույլ է տալիս ֆոնային և գլխավոր հոսքերին աշխատել անկախ, և կանխում է deadlock-ը։