Multithreading: Jak použít třídy synchronizace
Synchronizační prostředek přístupu mezi vlákny je obecným problémem při psaní aplikací s více vlákny. Mají-li dva nebo více vlákna současně přístup, mohou stejná data vést k nežádoucím a nepředvídatelným výsledkům. Například, jedno vlákno může aktualizovat obsah struktury, zatímco jiné vlákno čte obsahy stejné struktury. Není známo, jaká data čtecího vlákna bude obdrženo: stará data, nově zapsaná data nebo případně kombinace obou. Knihovna MFC poskytuje řadu synchronizačních tříd a tříd synchronizačního přístupu na pomoc při řešení tohoto problému. Toto téma vysvětluje třídy, které jsou k dispozici a jak je použít k vytvoření vlákna bezpečné třídy v typické aplikaci s více vlákny.
Typická aplikace s více vlákny má třídu, která představuje prostředek ke sdílení mezi vlákny. Správně navržena plně vláknově bezpečná třída nevyžaduje, aby jste volali jakékoliv funkce synchronizace. Vše je zpracováváno interně ke třídě, což Vám umožní soustředit se na to, jak nejlépe využít třídu, ne o to jak by mohlo dojít k poškození. Efektivní technika pro vytváření plně vláknově bezpečnou třídu, je sloučit synchronizační třídu do třídy prostředků. Sloučení tříd synchronizace do sdílené třídy je přímočarý proces.
Jako příklad si vezměme aplikaci, která udržuje propojený seznam účtů. Tato aplikace umožňuje prohlížet až tři účty v samostatných oknech, ale pouze jeden lze v jednom čase aktualizovat. Při aktualizaci účtu jsou aktualizovaná data odeslána přes síť do datového archivu.
Tato ukázková aplikace používá všechny tři typy tříd synchronizace. Protože umožňuje prohlížení až tří účtů v jednom okamžiku, používá 78w43c88(v=vs.100).md pro omezení přístupu ke třem objektům zobrazení. Při pokusu o zobrazení čtvrtého účtu aplikace buď čeká, dokud se jedno z prvních tří oken nezavře, nebo selže. Při aktualizaci účtu používá aplikace CCriticalSection k zajištění, že pouze jeden účet je aktualizován v jednu dobu. Po úspěšné aktualizaci signalizuje CEvent, což uvolní vlákno, čekající na signál události. Toto vlákno odesílá nová data do archivu dat.
Navrhování třídy bezpečné pro přístup z více vláken
Chcete-li, plně bezpečnou třídu pro přístup s více vlákny, nejprve přidejte příslušnou synchronizační třídu ke sdíleným třídám jako datový člen. V předchozím příkladu správy účtu měl být přidán datový člen CSemaphore do zobrazení třídy, datový člen CCriticalSection by měl být přidán k propojovacímu seznamu třídy a datový člen CEvent by měl být přidán do třídy úložiště dat.
Dále přidejte synchronizaci volání ke všem členským funkcím, které mění data ve třídě nebo v řízeném prostředku. V každé funkci by jste měli vytvořit buď objekt CSingleLock nebo objekt CMultiLock a volat tento objekt funkcí Lock. Když zámek objektu přejde z rozsahu a je zničen, volání destruktoru objektu Unlock pro vás uvolní prostředek. Samozřejmě můžete volat přímo Unlock chcete-li.
Navrhování Vaší třídy bezpečné pro přístup z více vláken tímto způsobem umožňuje použít více vláknovou aplikaci stejně snadno jako třídu bez bezpečného přístupu s více vláken, ale s vyšší úrovní bezpečnosti. Zapouzdření synchronizace objektu a synchronizace přístupu objektu do třídy prostředku poskytuje všechny výhody plného programování pro přístup z více vláken bez navracení zachování synchronizace kódu.
Následující příklad kódu ukazuje tuto metodu používající datový člen m_CritSection (typu CCriticalSection), deklarované ve třídě sdíleného prostředku a objektu CSingleLock. Synchronizace sdíleného prostředku (odvozená od CWinThread) je pokus o vytvoření objektu CSingleLock, použitím adresy objektu m_CritSection. Pokus je vyroben k uzamčení prostředku a pokud byl získán, práce je provedena na sdíleném objektu. Po dokončení práce je prostředek odemknut s voláním Unlock.
CSingleLock singleLock(&m_CritSection);
singleLock.Lock();
// resource locked
//.usage of shared resource...
singleLock.Unlock();
Poznámka
CCriticalSection na rozdíl od jiné knihovny MFC třídy synchronizace nemají možnost časově uzamknout žádost. Čekací lhůta pro uvolnění vlákna je neomezená.
Nevýhody tohoto přístupu jsou, že třída bude o něco pomalejší, než třída bez přidání objektů synchronizace. Také pokud je tam šance, že více než jedno vlákno smazalo objekt, sloučený přístup nemusí vždy fungovat. V takovém případě je lepší udržovat samostatné objekty synchronizace.
Informace o určování, které třídy synchrozizace používat v různých situacích, naleznete v tématu Multithreading: Kdy použít synchronizační třídy. Další informace o synchronizaci naleznete v tématu Synchronizace ve Windows SDK. Pro více informací o podpoře více vláken v knihovně MFC si prohlédněte Multithreading s C++ a knihovnou MFC.