Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: mysql_connect(): Headers and client library minor version mismatch. Headers:50562 Library:100020 in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: Cannot modify header information - headers already sent by (output started at /home/www/novacisko.cz/subdomains/bredy/init.php:11) in /home/www/novacisko.cz/subdomains/bredy/index.php on line 38
Multithreading v C++ (ve Win32) III - OOP a vlákna - Bredyho blog - Ondřej Novák
Bredyho blog - Ondřej Novák

Multithreading v C++ (ve Win32) III - OOP a vlákna

Pokračování dokumentace k Multithreading v C++ (ve Win32) - Tentokrát si povíme něco o tom jak začlenit vlákna do OOP


Kam vlákna patří v OOP

Objekty a vlákna, jak to spolu souvisí? Kromě toho, že vlákno reprezentujeme objektem to na první pohled žádnou spojitost nemá.

V OOP známe termín spustitelný objekt. Jedná se vlastně o instanci úlohy, která provádí určitý program krok za krokem. Vztaženo obecně, jakákoliv aplikace je spustitelný objekt. V pravém OOP je vlastně toto speciální objekt, protože OOP samo o sobě o provádění programu nemluví. To pouze řeší život objektů (vznik a zánik) a vztahy mezi nimi.

Běhové prostředí objektu, a tady se právě myslí ono vlákno, přitom vlastní pouze a jen pouze tento objekt. To může vlákno propůjčovat jiným objektům (a tím jim dává šanci pracovat), ale musí mít nad vláknem kontrolu. Z tohoto pohledu je vlákno prostředkem typu private/protected. Na základě tohoto pohledu lze odvodit pravidla přístupu vlákna k proměnným.

V multithreadové aplikaci bývá nejčastějším problémem synchronizace. Přístup ke globálním proměnným se musí vždycky synchronizovat. O tom kdy přístup synchronizovat by měl rozhodnout právě objekt, který vlákno vlastní. Protože jedině on má přehled o tom, co se zrovna unitř vlákna děje, a která proměnná musí být synchronizována. Proto přístup k proměnným, ke kterým má přístup různá vlákna (zde je myšleno jak vlákno které objekt vlastní, tak vlákno, které objekt řídí) musí bezpodmínčně být soukromé nebo chráněné (private nebo protected). Přístup k těmto proměnným je pak zajišťován přes Get/Set funkce. Výjimkou mohou být proměnné, které již mají mechanismy synchronizace vestavěné, ale i tady je lepší nepřistupovat k proměnným přímo. Navíc vestavěná synchronizace může práci s těmito proměnnými zpomalit.

Synchronizace přístupu může být jednoduchá, postačí 1 kritická sekce, aktivovaná pokaždé při čtení nebo změny sdílené proměnné (proto není nutné řešit synchronizaci uvnitř běžných objektů, jelikož zde se synchronizace řeší). Tam kde by hrozilo, že zamykání bude častější nebo "na delší dobu", je lepší použít MutexBlocker nebo semafory. V časově kritických algoritmech je lepší mít pro každou proměnnou vlastní zámek. Pak funkce která používá např. proměnnou A nemusí čekat až jiné vlákno přestane pracovat např. s proměnnou B.

Shrnutí

  1. Vlánko je soukromým majetkem spustitelného objektu.
  2. Přístup k proměnným, které jsou sdílené z vně i uvnitř vlákna musí být private nebo protected a v obou případech používat Set/Get funkce
  3. Přístup synchronizovat kritickou sekcí, mutexem nebo semaforem.
  4. Synchronizační prostředky jsou také soukromé nebo chráněné, "vnější svět" nesmí manipulovat s těmito prostředky přímo.

Příklad

class Executable: public ThreadBase
{
mutable MiniCriticalSection _lock;
double _varA;
public:
void SetA(double a)
{
_lock.Lock();
_varA=a;
_lock.Unlock();
}
double GetA() const
{
_lock.Lock();
double a=_varA;
_lock.Unlock();
return a;
}
}

Komunikace mezi vlákny

Knihovna MultiThread nabízí jednoduchý prostředek pro komunikaci mezi vlákny. Jedná se o systém zasílání zpráv.

Říci spustitelnému objektu, že má něco udělat může být problém. Pokud spustitelným objektem je objekt třídy ThreadBase, pak tento objekt má k dispozici pouze jedno vlákno (samozřejmě spustitelný objekt může vlastnit více vláken - pak to není nic jiného, než objekt obsahující pole pomocných objektů mající k dispozici jedno vlákno), tak lze objekt donutit k činnosti pouze jednou a pak až v okamžiku, když vlákno dokončí svou práci. Vlákno nelze standardně přerušit ani mu nijak z vnějšku vnutit jiné chování (pokud to objekt nijak neimplementuje).

Knihovna MultiThread zavádí systém posílání zpráv. Vláknům dává možnost využít zásobníků zpráv (schránka, mailbox) kam ostatní vlákna vkládají své požadavky. Vlákno požadavky vyzvedává a provádí. Jako zpráva pak slouží instance třídy jenž dědí určité rozhraní

IThreadMessage
Představuje zprávu. Zprávou se zde rozumí i přímo funkce, která se má vykonat v kontextu volaného vlákna.
MessageTarget
Představuje třídu, které lze zasílat zprávy. Má k dispozici funkci SendMsg. Funkce zařadí zprávu do fronty. Druhé vlákno (vlastnící tento objekt) má k dispozici funkce pro zpracování těchto zpráv.
MessageThreadClass
Představuje implementaci MessageTarget - v podobě třídy, která přebírá vlákno a instaluje pumpu zpráv. Vlákno je zastavováno při čekání na zprávy a slouží vlastně jako server pro tyto zprávy. Třídu lze rozšířit i tak, aby zprávy předávala více vláknům.
MessageThread
Je templatovanou implementací MessageThreadClass aplikovatelnou na libovolnou třídu dědící ThreadBase. Implementuje metodu Run tak aby vlákno bylo po celou dobu připraveno přijímat zprávy. Umožňuje také přechod do úsporného režímu, kdy je v případě delší nečinnosti pomocné vlákno ukončeno aby instance nazabírala prostředky OS.

IThreadMessage

Jednoduché rozhraní implementující zprávu. Zpráva přímo obsahuje programový kód, který se má ve vlákně vykonat. Vlákno pouze tento kód vyvolá.

Kód je definován ve funkci Run.

Rozhraní dále disponuje referenčním čítačem, který zajistí likvidaci instance zprávy v okamžiku, kdy ani jedno vlákno tuto zprávu nepotřebuje.

Definovány jsou standardní metody Reply a WaitForReply, jenž musí potomek nadefinovat, chce-li je využít. Pak WaitForReply pozastaví vlákno do doby než druhá strana zavolá Reply.

MessageTarget

Třída implementuje frontu zpráv a disponuje těmito funkcemi

SendMsg
Zařazuje zprávu do fronty a informuje druhou stranu, že nová zpráva je k dispozici. Tuto funkci zpravidla volá cizí vlákno, chce-li v rámci druhého vlákna zavolat nějakou funkci.
PumpMessage
Vyzvedne a zpracuje jednu zprávu, je-li nějaká zpráva připravena.
PumpAllMessages
Vyzvedne a zpracuje všechny zprávy ve frontě.
SignalExit
Pošle vláknu speciální zprávu. Ta vlákno infromuje, že je čas ukončit činnost bez ohledu na stav fronty.
IsExitSignaled
Funkcí lze testovat stav exit signálu
AnyMessage
Vrací stav fronty.

UIMessageTarget

Představuje MessageTarget implementující příjem zpráv na libovolném UI vlákně ve Win32. Po inicializaci nebo instalaci je schopna volat funkce v kontextu UI vlákna, což bývá někdy důležité, například, pokud je potřeba z nějakého pracovního vlákna aktualizovat UI prvky.

MessageThreadClass

Oproti MessageTarget implementuje zastavování vlákna v případě, že ve frontě nečeká žádná zpráva. Funkce PumpAllMessages tak zastaví běh vlákna do doby, než dorazí zpráva, nebo dokud neuplyne zadaný čas. V případě, že je přijata zpráva, zpracuje se a opět se čeká na další zprávy nebo zadaný čas. V případě, že je přijat signál exit, je čekání zkráceno.

MessageThread

Představuje kompletní řešení objektu vlákna, který zpracovává zprávy. Po inicializaci je v tzv. úsporném režimu kdy nezabírá prostředky OS. V případě, že objekt přijme první zprávu, spustí interní vlákno a zprávu zpracuje. Zpracuje takto všechny další zprávy, které dorazí do fronty. Pokud je fronta vyprázdněna, počká zadaný čas, než je přepnut do úsporného režimu a vlákno zastaveno.

Výhody a nevýhody zasílání zpráv

Zasílání zpráv má jedno hlavní výhodu a to, že není nutné tak často používat synchronizace. Vlákno pracuje jen na základě zprávy a s daty, které získalo přímo v instanci. Nepotřebuje přistupovat k žádným dalším datům, a může si pracovat takřka "na vlastním písečku". Takto je maximálně odděleno. Samozřejmě že je možné, že určité proměnné sdílí skrze instanci zprávy, pak je synchronizace řešena jen v této zprávě.

Nevýhodou zasílání zpráv je velká režie při alokaci a dealokaci zpráv, proto je tento mechanismu výhodný, pokud zpracování zprávy zabere významně více času.

POZOR: Nová verze:

MultiThread 2 <-- Stahujte zde!!!

vytvořeno: 7.6.2006 20:30:46, změněno: 27.3.2007 03:06:41
Jsou informace v článku pro Vás užitečné?
  • (10)
  • (2)
  • (1)
  • (3)
  • (2)
Nick nebo OpenID
Vzkaz
 
25.7.2016 18:41:56

phNtdhxTiH7B

It&#8217;s a shame you do2&78n1#;t have a donate button! I&#8217;d without a doubt donate to this excellent blog! I suppose for now i&#8217;ll settle for bookmarking and adding your RSS feed to my Google account. I look forward to new updates and will share this site with my Facebook group. Chat soon!
25.7.2016 18:37:19

rj7VmmUcq4

Haha, that Henny Penny: she looks so cute in her new outfit! And with a Dutch theme, even better! (I&#8217;m Dutch myself)Love your hoodie as well Anna. I&#8217;ve bought some knit fabrics but am still too scared to get started. I&#8217;m never quite certain which stitch to use, my machine has several to choose from&#8230;Have a great wekdne-e!Marjan/ Seattle

Podobné články

Multithreading v C++ (ve Win32) II - ThreadHook

Pokračování dokumentace k Multithreading v C++ (ve Win32)

Multithreading v C++ (ve Win32)

Představení knihovny pro multithreading v C++. Jedná se čistě o objektový návrh multithreadingu inspirovaný Javou. Mnoho programátorům může usnadnit práci s vícero vlákny ve WinApi.

MultiThread 2

Knihovna MultiThread-2.0

Jak bezpečně ukončit vlákno z DllMain

Kdo už se s tím setkal, určitě nad tím strávil hodně času. Jak to že není možné bezpečně ukončit vlákno z DllMain? Proč aplikace skončí v deadlocku? To opravdu neexistuje jiné řešení?

Linux vs Windows: Procesy

V prvním díle seriálu Linux vs Windows se zaměříme na úplně nejzákladnější službu OS. Spouštění a správa procesů.
Reklama: