Hardcore C# hádanka

Tomáš Jecha, MVP, MCSD       18.05.2010       C#       12137 zobrazení

Při programování více vláknových aplikací jsem se poprvé setkal s jedním poměrně nepříjemným jevem, o který se s vámi chci podělit.

Tak schválně, kdo z vás zná opravdu dobře C#? Prohlédněte si následující kód:

     class Program
    {
        
static bool exit = false;

        
static void Main(string[] args)
         {
            
Console.WriteLine("Začátek.");

            
var loopThread = new Thread(LoopTilExit);
             loopThread.Start();

            
Thread.Sleep(500);
             exit =
true;

             loopThread.Join();
            
Console.WriteLine("Konec.");
            
Console.ReadLine();
         }

        
static void LoopTilExit()
         {
            
int a = 0;
            
while (!exit)
             {
                 a++;
             }
         }
     }

    Je v něm všechno v pořádku? … Odpověď zní – ne, není. Je v něm poměrně závažná chyba.

    Zkuste mi odpovědět na tyto otázky:

    • Za jakých podmínek se následující kód zadeadlockuje?

    • Proč se to stane a proč se to stane jen někdy?

    • Jak tomu zabránit?

        Odpovědi pište na tomas[zavinutá-rybička]jecha.net. První korektní řešitel bude odměněn drobným dárkem.

         

        hodnocení článku

        -1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

         

        Nový příspěvek

         

        !deadlock

        Zdar, i kdyz budu resurektovat 6 let stary thread, taky si myslim, ze tahle kondice neni deadlock. Jasne, chapu, jak to myslis - logicky ten druhy thread ceka na nastaveni flagu, ktery provede ten hlavni, ale neni to fyzicky vazane na to vlakno. Zatimco ten .Join() skutecne ceka na vlakno, prace toho druheho je inkrement promenne "a" test na promennou "exit" - jejiz nastaveni teoreticky muze provest treba nejaky treti thread, ktery tady nemame. Proto druhy thread neni lockovany hlavnim, jen si kona svoji - samozrejme silne nesmyslnou - cinnost.

        Zdravi Trpaslik; a hodne stesti do budoucna :-)

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        Ahoj Trpo, je to už dlouho, ale v zásadě šlo IMHO o toto:

        - spustí se vlákno LoopTilExit a začne kontrolovat variable exit a nacachuje si jí

        - mezitím uplyne 500ms a první vlákno hodnotu variable změní a následně čeká na ukončení vlákna LoopTilExit

        - vlákno LoopTilExit se nemusí o změně hodnoty variable dozvědět, protože ji má nacachovanou a nikdy se neukončí

        - první vlákno stále čeká na ukončení druhého

        Takže vlákna na sebe chybou čekají.

        Řešením by bylo použít volatile, které slouží právě pro tyto účely. Nebo osobně bych raději použil nějaký ManualResetEvent pro sémanticky přesnější vyjádření smysl proměnné.

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        Diskuse: Hardcore C# hádanka

        Je tu drobná terminologická nepřesnost v zadání. Určitě nemůže nastat deadlock - deadlock je situace, kdy jedno vlákno čeká na druhé a druhé na první, případně víc vláken na sebe čeká v cyklu. Tady druhé vlákno nečeká na první, takže fakticky nejde o deadlock, jen o pouhé zacyklení.

        nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

        Nemám rád slovíčkaření - a tohle rozhodně velké slovíčkaření je.

        Ale i tak nesmyslím, že máš pravdu. Protože ony totiž ty vlákna na sebe ve skutečnosti opravdu vzájemně čekají. A tím se splňuje podstata definice deadlocku. A je už úplně jedno, jestli je to čekání realizováno cyklem nebo čímkoliv jiným (událostí ukončení vlákna atp.).

        Jen pro upřesnění, aby v tom bylo jasno - běží vedle sebe dvě vlákna - vedlejší vlákno čeká na signál přes proměnnou z hlavního vlákna a zároveň hlavní vlákno čeká na ukončení vedlejšího vlákna. Ale nechci se v tom tolik šťourat, abych to neprozradil.

        Až pochopíš, proč je to vlastně deadlock, tak uvidíš i důvod, proč nastává.

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        O deadlocku se mluví v případě pasivního čekání, kdy se čeká na nějakém zámku, mutexu nebo jiném synchronizačním primitivu, prostě čeká se na uvolnění nějakého sdíleného prostředku.

        Tady máš čekání aktivní, jedno vlákno stojí, ale druhé pořád běží a vytěžuje procesor. Co konkrétně to vlákno dělá, není podstatné, ono prostě běží. Definici deadlocku to zkrátka nevyhovuje. Jasně, je to slovíčkaření a taky ho nemám rád, omlouvám se.

        nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

        Pokud vím, tak deadlock není omezen jen na pasivní čekání, ačkoliv je to v 99% případech pravda. Pokud to tak je, tak oba známe jinou definici. Jenže to už se vracíme ke slovíčkaření. Navíc nemyslím, že v tomto případě je termín deadlock úplně od věci, protože ono zacyklení vzniká právě kvůli čekání na druhé vlákno.

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        Toto opravdu není deadlock :-)

        Na deadlock jsou potřeba minimálně dva zdroje a dva procesy.

        Ke zdrojům může přistupovat v jednu chvíli jen jeden proces.

        Každý z procesů drží jeden zdroj, a každý z procesů chce přístup i k druhému zdroji. Takhle nám to vtloukali do hlavy na FI MU, tak to snad bude pravda :-D.

        http://cs.wikipedia.org/wiki/Deadlock

        http://cs.wikipedia.org/wiki/Nekone%C4%8...

        Slovíčkaření toto není, nazývejme věci pravými jmény.

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        To, že vás něco učí ve škole (i když je vysoká), nemusí nutně znamenat, že to je pravda.

        Na deadlock opravdu nemusí být dva procesy, stačí dvě vlákna.

        Wikipedia také není úplně spolehlivý zdroj informací.

        nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

        Diskuse: Hardcore C# hádanka

        ja som javista a C# vobec nepouzivam, ale tipoval by som to na "problem" toho statickeho exit flagu, ktory nie je atomicky a preto moze nastat to, co popisujes.

        BTW: naozaj obaja nemate radi slovickarenie? :)

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        Chtěl jsem se zeptat zda-li bude někdy vyhlášena správná odpověď a případní výherci soutěže?

        děkuji

        nahlásit spamnahlásit spam 0 odpovědětodpovědět

        je treba pouzivat modifier 'volatile' pro policku 'field', jinak JIT kompilator muze nacachovat policku do registru.

        nahlásit spamnahlásit spam 0 odpovědětodpovědět
                               
        Nadpis:
        Antispam: Komu se občas házejí perly?
        Příspěvek bude publikován pod identitou   anonym.

        Nyní zakládáte pod článkem nové diskusní vlákno.
        Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

        Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

         

        • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
          Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
        • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

        přihlásit pomocí externího účtu

        přihlásit pomocí jména a hesla

        Uživatel:
        Heslo:

        zapomenuté heslo

         

        založit nový uživatelský účet

        zaregistrujte se

         
        zavřít

        Nahlásit spam

        Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

        Nahlásit Zrušit

        Chyba

        zavřít

        feedback