Vícevláknové aplikace a události   zodpovězená otázka

Komponenty, Threading, .NET

Dobrý den. Chtěl bych se zeptat na něco málo z teorie vícevláknových aplikací:

Pokud mám takovou aplikaci, tak předpokládám, že pokud v průběhu jejího vykonávání volám nějakou metodu (funkci či podprogram), že tyto jsou vykonávány ve stejném vlákně, ve kterém běží proces, ze kterého metodu volám.

Jak je to ale s událostmi? Pokud v nějakém procesu (běžícím ve vlákně A) vyvolám událost (např. pomocí Raise event...), v jakém vlákně se mi uvedená událost obslouží? V tom samém? V hlavním? S tím dost úzce souvisí i nutnost umístění "prostoru" pro obsloužení události (application.doevent). Pokud vyvolám událost pomocí toho Raise event v jiném než hlavním vlákně aplikace, je zapotřebí použít v tomto vlákně doevent, nebo dojde k obsloužení ve vlákně jiném, takže prostor pro toto obsloužení si vytvoří operační systém sám?

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

Dobrý den,

pokusím se trošku objasnit teorii vláken pro tento konkrétní případ. Pokud spustíte klasickou Windows aplikaci s formulářem, jedná se o tzv. single-threaded apartment (jedno vláknové zázemí) - čili obsluhování událostí formuláře, jeho překreslování atp. běží vše v jednom vlákně. Proto při provádění dělší operace okno jakoby přestane reagovat - vytuhne. DoEvents se používá pro to, aby se umožnilo vláknu provést běžné úlohy jako překreslení okna, reakce na události atp. Až toto proces udělá, přejde se zpět do vašeho kódu. V případě, že déle trvající kód necháte provést v jiném vlákně, formulář bude reagovat úplně normálně.

A k druhé části otázky. Když zavoláte funkci nebo vyvolání události (přes RaiseEvent), tak se provede vše ve stejném threadu jako ze kterého je zavolána.

A poslední poznámka: některé vlastnosti a funkce formuláře nejsou z jiných vláken než STA (single-threaded apartment) přístupné (z důvodů tzv. cross-thread bezpečnosti).

Omlouvám se za strohost a (asi) dost jak gramatikých tak stylistických chyb, ale nemám teď bohužel moc času. Jakékoliv nejasnosti rád vysvětlím.

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

Příjemný dobrý den,

děkuji za odpověď - netřeba se omlouvat za strohost, ta vůbec není na závadu jinak věcnému sdělení, spíše naopak.

Díky Vaší radě jsem došel ke zjištění, že opět toho vím více o tom, kolik toho ještě nevím. Přiznám se, že jsem původně začínal mít mlhavou představu o fungování vícevláknových aplikací, leč nyní, díky Vám, zjišťuji, že špatnou.

Dle Vámi napsaného jsou tedy z hlediska provádění zcela rovnocené zápisy:

public class Třída
    public Event udalost()
    dim druheVlakno as thread

  private sub metoda1()
    ...
    druheVlakno = new thread(addressOf metoda2)
    druheVlakno.Start()
    ...
    ' pokračování metody 1, které se provádí bez ohledu na
    ' právě spuštěné  druhé vlákno
    ' a nečeká na nic
    ...
  end sub


   public sub metoda2()
   ...
   ' běžný způsob zavolání podprogramu:
   metoda3()
   ' provede se kompletně celá volaná metoda3(),
   ' až po jejím ukončení pokračuje provádění dalšího
   ' těla metody 2 (vše probíha na "druhemVlakně",
   ' takže provádění původní metody1 (z hlavního vlákna)
   ' není nijak ovlivňováno
   ...
   ...
   ' vyvolání události
   raiseevent udalost()
   ' dle vašeho vysvětlení proběhne tedy úplně totéž,
   ' jako v předchozím a další příkazy metody2 za voláním
   ' raiseevent se provedou až po kompletním zpracování 
   ' metody3
   ...
   ' pokračování metody2
   ...
   end sub

  private sub metoda3() handles udalost
    ...
    telo pro vykonani 
    ...
  end sub

end class

Z toho by ovšem vyplývalo, že běžné volání funkcí (průběžné programování) a vyvolávání událostí (událostmi řízené programování) jsou zcela totožné a jediné, v čem se liší, je syntaxe, kdy u běžného programování přiřazuji konkrétné název volané funkce na straně volání této funkce (funkci již volám jménem), kdežto u event handled programování toto přiřazení provádím až na straně volané funkce (vazba přes "handles"), ale po stránce konkrétního následného vykonávání kódu jsou obě metody zcela rovnocenné?

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

Ano, pochopil jste to správně. Eventy jsou jen prakticky jen volání procedur nebo funkcí, které jsou na event připojené pomocí klíčového slova Handles.

Rozdíl je jen v tom, že eventy (události) mají sloužit jako informační prostředek o tom, že se něco stalo. Výhodou je, že nemusíte předem vědět jaký kód se bude spouštět. Například event OnClick při stisknutí tlačítka. Pro chod tlačítka to nic neznamená, ale nám to dává možnost jak poznat, že bylo tlačítko stisknuté - "přivázali" jsme si totiž na jeho event nějakou svojí proceduru ovládající, co se stane po klepnutí na něj. Eventy jsou jen prostředek objektového programování pro přehlednější a elegantnější psaní kódu - v jednom souvětí: nemusíte přepisovat kód tlačítka, stačí jen "chytat" jeho události.

Doufám, že jsem to ještě více nezamotal.

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

Vůbec ne, děkuji, již je mi to jasné, nebo alespoň podstatně jasnější.

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

Ještě bych si dovolil v této souvislosti jednu doplňující otázku:

Jak jsem teď pochopil, vyřízení události běží tam, odkud je dán k této události pokyn. Je to celkem jasné a i pro mne, jako laika, dokonce pochopitelné u vlastních metod.

Jak je to ale třeba u FORMu? Na formulář, případně do něj vnořené Controlls je navázána fůra událostí. Všechny jsou tedy navázány na jedno vlákno (jak jste psal o "jednovláknovém zázemí"). To je, si myslím, taky celkem pochopitelné.

Můj dotaz míří ale tam, pokud si spustím WinForm aplikaci, je nějaký mechanismus, jak z kódu této aplikace spustit druhý formulář s vlastní "WinForm" funkčností tak, aby tento formulář využíval opět svého "jednovláknového zázemí, ale ve svém vlastním vlákně (rozdílném od vlákna "stvořitele")? Zkrátka aby si oba formuláře žily víceméně samostatně (což není problém zvládnout díky Vašim radám v některé z předchozích diskusí), ale, hlavně, aby si každý i své eventy obhospodařoval v tomto svém vlastním vlákně? De facto, aby se vytvořila funkčnost aplikace taková, jako kdybych vytvořil samostatně (WinForm) aplikaci B, zkompiloval ji do spustitelného souboru a tento pak v rámci aplikace A spustil (přes process.start) v pomocném vlákně.

Nebo je takováto úvaha zcela zcestná a pokud chci mít aplikaci s několika moduly, u kterých potřebuji, aby se vzájemně neovlivňovaly ani při řešení jednotlivých eventů, musím tyto konflikty vyřešit sám tak, že při zachycení eventu jenom spustím (do jiného vlákna) další metodu, která provede vlastní ošetření události, ovšem i s tím, že budu muset důsledně řešit i problémy s cross-thread bezpečností?

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

Zkusím odpovědět velmi stručně. Pokud spustíte z jednoho formuláře další, oba běží pořád v jednom vlákně. Obecně se doporučuje nové vlákno používat jen na akce, které trvají delší dobu. Ale pokud chcete mít dva nezávislé formuláře,tak není problém oba pustit v každý ve svém vlákně. Například kódem:

    Dim th As New Threading.Thread(AddressOf newWindow)
    Sub ZobrazDruhyFormularVeVlastnimVlakne()
        th.Start()
    End Sub
    Public Sub newWindow(ByVal state As Object)
        Form2.ShowDialog()
    End Sub

Ale je pravda, že potom přistupovat z jednoho do druhého může být problematické.

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

Díííky, toť přesně to, nač jsem se tázal.

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

Jen bych podotknul, že vždy je třeba mít se na pozoru před voláním vlastností a metod ovládacích prvků z jiného vlákna, než ze kterého byly vytvořeny. V .NET 1.0/1.1 to šlo, ve 2.0 nastává vyjímka. Když už musíte něco volat z jiného vlákna než ze kterého to bylo vytvořeno, musí se použít nejlépe SynchronizationContext, nebo If InvokeRequired Then BeginInvoke...

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • 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