Singleton obsah. n Motivace. n Základní myšlenka. n Implementace. n Problémy. n Dědičnost. n Obecná implementace. n Shrnutí.

Podobné dokumenty
Singleton obsah. Motivace Základní myšlenka Implementace Problémy. Dědičnost Obecná implementace Shrnutí. destrukce vícevláknovost

Zdeněk Pavlů

Jazyk C++ I. Šablony 2

Programování v C++ 2, 4. cvičení

<surface name="pozadi" file="obrazky/pozadi/pozadi.png"/> ****************************************************************************

PB161 Programování v jazyce C++ Přednáška 8

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

PB161 Programování v jazyce C++ Přednáška 4

PB161 Programování v jazyce C++ Přednáška 4

Generické programování

PREPROCESOR POKRAČOVÁNÍ

Více o konstruktorech a destruktorech

konstruktory a destruktory (o)

Jazyk C# (seminář 3)

Konstruktory a destruktory

Osnova přednášky. Programové prostředky řízení Úvod do C# II. Přístup ke členům. Členy (Members)

Programování v C++ 3, 3. cvičení

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Dynamika objektů. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze

Mělká a hluboká kopie

Programování v C++ 2, 8. cvičení

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Úvod Třídy Rozhraní Pole Konec. Programování v C# Hodnotové datové typy, řídící struktury. Petr Vaněček 1 / 39

Návrhové vzory. Jakub Klemsa, Jan Legerský. 30. října Objektově orientované programování.

PB161 Programování v jazyce C++ Přednáška 10

Polymorfismus. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 30.března

NPRG031 Programování II 1 / :25:46

Jazyk C++ II. Šablony a implementace

NMIN201 Objektově orientované programování 1 / :36:09

Abstraktní datové typy

Jazyk C++ 1. Blok 3 Objektové typy jazyka C++ Třída. Studijní cíl. Doba nutná k nastudování. Průvodce studiem

Programování v C++ 1, 5. cvičení

Zpracoval:

Jazyk C++ I. Šablony 3

PB161 Programování v jazyce C++ Přednáška 10

Základy C++ I. Jan Hnilica Počítačové modelování 18

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

C++ 0x aka C++11. Základním kamenem je třída std::thread

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

Základy jazyka C# Obsah přednášky. Architektura.NET Historie Vlastnosti jazyka C# Datové typy Příkazy Prostory jmen Třídy, rozhraní

Správa paměti. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta, 2016

přetížení operátorů (o)

PB161 Programování v jazyce C++ Přednáška 7

PB161 Programování v jazyce C++ Přednáška 7

přetížení operátorů (o)

Úvod do programovacích jazyků (Java)

, Brno Připravil: David Procházka Návrhové vzory

Pokročilé programování v jazyce C pro chemiky (C3220) Statické proměnné a metody, šablony v C++

Jazyk C++ I. Šablony

PROGRAMOVÁNÍ V C++ URČENO PRO VZDĚLÁVÁNÍ V AKREDITOVANÝCH STUDIJNÍCH PROGRAMECH ROSTISLAV FOJTÍK

IB111 Programování a algoritmizace. Objektově orientované programování (OOP)

Programování v C++, 2. cvičení

Programování v C++ 2, 7. cvičení

Abstraktní třídy, polymorfní struktury

Programování v C++ 1, 6. cvičení

Správa paměti. doc. Ing. Miroslav Beneš, Ph.D. katedra informatiky FEI VŠB-TUO A-1007 /

PB161 Programování v jazyce C++ Přednáška 5

Dědičnost. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 23.března

OMO. 4 - Creational design patterns A. Singleton Simple Factory Factory Method Abstract Factory Prototype Builder IoC

Zápis programu v jazyce C#

IRAE 07/08 Přednáška č. 1

Jazyk C++, některá rozšíření oproti C

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

PROGRAMOVÁNÍ V C++ CVIČENÍ

Vláknové programování část V

PB161 Programování v jazyce C++ Přednáška 9

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

PŘETĚŽOVÁNÍ OPERÁTORŮ

Jazyk C# (seminář 6)

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

PB161 Programování v jazyce C++ Přednáška 5

Semin aˇr Java N avrhov e vzory Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Duben 2008 Radek Koˇc ı Semin aˇr Java N avrhov e vzory 1/ 24

Spojová implementace lineárních datových struktur

Abstraktní datové typy: zásobník

Abstract Factory úvod

Dynamická identifikace typů v C++.

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Datové struktury. alg12 1

Dynamicky vázané metody. Pozdní vazba, virtuální metody

PB161 Programování v jazyce C++ Přednáška 9

Class loader. každá třída (java.lang.class) obsahuje referenci na svůj class loader. Implementace class loaderu

Programování v Javě I. Leden 2008

Programování v jazyce C a C++

PB161 Programování v jazyce C++ Přednáška 9

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Objektové programování

Semin aˇr Java N avrhov e vzory Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Duben 2009 Radek Koˇc ı Semin aˇr Java N avrhov e vzory 1/ 25

Seminář Java II p.1/43

Programování v Javě I. Únor 2009

Jazyk C++ II. Výjimky

Kód, který se nebude často měnit

PB161 Programování v C++ Proudy pro standardní zařízení Souborové proudy Paměťové proudy Manipulátory

Datové typy v Javě. Tomáš Pitner, upravil Marek Šabo

Bridge. Známý jako. Účel. Použitelnost. Handle/Body

Základní datové struktury

Architektura COM. Historie Component Object Model (COM) Komunikace s komponentami Rozhraní komponent COM komponenty v.net.

Vlákna a přístup ke sdílené paměti. B4B36PDV Paralelní a distribuované výpočty

Dědění, polymorfismus

Ukazka knihy z internetoveho knihkupectvi

Transkript:

Singleton

Singleton obsah n Motivace n Základní myšlenka n Implementace n Problémy q destrukce q vícevláknovost n Dědičnost n Obecná implementace n Shrnutí

Singleton motivace n Co mají následující příklady společného? q DatabaseConnectionPool přiděluje spojení do DB jednotlivým částem aplikace q WindowManager v okenním systému existuje jeden objekt spravující okna q Keyboard, display, log (KDL) q PrinterSpooler více tiskáren, jeden manažer q FileSystem q System clock n Odpověď: q Třídy řešící tyto problémy vyžadují jedinou instanci. Mít více instancí je nežádoucí až nebezpečné. q Měly by být lehce přístupné z libovolného místa.

Singleton naivní implementace základní myšlenka n Globální proměnná q zaručuje globální přístupový bod q znepřehledňuje namespace a kód q nedokáže zaručit jedinou instanci objektu n Statická data + statické metody q zaručuje globální přístupový bod q zaručuje jedinou instanci q problém rozšiřitelnosti statické metody nemohou být virtuální q problém inicializace (závislosti) q problém úklidu (kdo to má dělat) n Singleton q třída se o svou jedinou instanci stará sama q inicializace: konstruktor q úklid: destruktor

Singleton požadavky n Zaručení jediné instance q zakázat vytvoření více instancí class Singleton { public static Singleton instance(); q zakázat kopírování existující instance q zakázat rušení q instanci spravuje singleton n Globální přístupový bod q použití na libovolném místě kódu q přístup poskytován samotnou třídou protected Singleton(); protected Singleton(final Singleton s); /* C++ Singleton& operator=(const Singleton&); virtual ~Singleton(); */... ; n Možnost rozšiřitelnosti q bez nutnosti zásahu do kódu předka q zachovává všechny nástroje objektového programování n virtuální metody, abstraktní metody, přetěžování metod q pomocí šablon

Singleton implementace class Singleton { private static Singleton instance; public static Singleton instance() { if (instance == null) { instance = new Singleton; return instance; public void dosomethinguseful() {... protected Singleton() {... protected Singleton(final Singleton s); /* C++ Singleton& operator=(const Singleton&); ~Singleton() {... */ Ukazatel na instanci si spravuje třída sama. Je static Statická metoda pro přístup k jediné instanci. Instance se vytvoří při prvním volání instance() až když je to potřeba. Konstruktor nesmí být public. Inicializuje třídu. Volán jenom zevnitř třídy. Destruktor nesmí být public, někdo by mohl smazat instanci. void main(string[] args) { Singleton.instance().doSomethingUseful();... Jednoduchý příklad použití.

Singleton problémy n GoF '95 q relativně jednoduchý vzor q od té doby rozsáhlé diskuse q Vlissides '98: n I used to think it was one of the more trivial of our patterns... Boy, I was wrong! n Problém destrukce (lifetime) q zodpovědnost za zrušení q kdy je objekt zrušen q některé objekty je potřeba mít přístupné vždy n Problém vícevláknových aplikací q zabezpečení jedinečnosti n Dědičnost

Singleton destrukce Ostrich n 'Ostrichovo' řešení (leaking singleton) q problém destrukce ignorovat q statická paměť se uvolní automaticky při ukončení procesu q co když je třeba říci vzdálené straně že končím? q jako každá kulturní třída by měl mít destruktor n zápis do logu, uzavření spojení, odhlášení,... q diskuze o tom co je a co není leak (memory leak, resource leak) n V čem je problém? q destruktor se nezavolá q ukládáme statický ukazatel, ne statický objekt

Singleton destrukce killer n Idea q ukazatel zabalit do třídy starajíci se o destrukci q kompilátor se stará o zrušení statického objektu singletonkiller, který ve svém destruktoru instanci Singleton zabíjí

Singleton destrukce killer (C++) class SingletonKiller { public: void setsingleton(singleton* _instance) { instance = _instance; Singleton* getsingleton() { return instance; ~SingletonKiller() { delete instance; private: static Singleton* instance; ; class Singleton { public: static Singleton* instance(); private: Singleton(); ~Singleton(); Singleton(const Singleton&); Singleton& operator=(const Singleton&); ; static SingletonKiller singletonkiller; Singleton* SingletonKiller::instance = 0; SingletonKiller Singleton::singletonKiller; n Idea q ukazatel zabalit do třídy starajíci se o destrukci q kompilátor se stará o zrušení statického objektu singletonkiller, který ve svém destruktoru instanci Singleton zabíjí 2. destruktor killera killer obsahuje ukazatel na náš singleton 3. destruktor singletonu 1. destrukce statické proměnné Singleton* Singleton::instance() { if (!singletonkiller.getsingleton()) { singletonkiller.setsingleton( new Singleton); return singletonkiller.getsingleton();

Singleton Meyers (C++) n Scott Meyers q místo operátoru new, statická lokální proměnná q instanci nedržíme ve statickém ukazateli q funkce vracející referenci na statický objekt ve funkci class Singleton { public: static Singleton& instance() { static Singleton inst; return inst; private: Singleton() {... Singleton(const Singleton&); Singleton& operator=(const Singleton&); ~Singleton() {... ; 2. inicializace statického objektu pouze při prvním průchodu registrace atexit 4. návrat zkonstruovaného objektu 3. konstruktor objektu 6. destruktor objektu int main(int argc, char** argv) { Singleton& s = Singleton::instance();... 1. zavolá se metoda 5. konec programu, destrukce statických proměnných

Singleton funkce atexit = generované kompilátorem n Odstraňování statických proměnných q LIFO nejdříve se odstraní naposledy inicializované q int atexit(void*(pfunction)()); q při vytváření objektu se zaregistruje funkce pro zrušení q při ukončení programu se postupně zavolají registrované funkce funkce generované kompilátorem Singleton& Singleton::instance() { extern void constructsingleton(void* memory); extern void destroysingleton(); static bool initialized = false; static char buffer[sizeof(singleton)]; if (! initialized) { constructsingleton( buffer); atexit( DestroySingleton); initialized = true; proměnné generované kompilátorem buffer obsahuje Singleton volání funkce constructsingleton() zavolá konstruktor na paměti buffer return *reinterpret_cast<singleton*>( buffer); zaregistruje destrukci

Singleton problém s pořadí destrukce n Dead reference problem q při nevhodném pořadí mohou vzniknout reference na neexistující objekty q příklad: singletony Keyboard, Display, Log n vytvoření instance Log pouze při chybě inicializace Keyboard inicializace Display s chybou inicializace Log a zapsání chyby konec programu destrukce Log destrukce Display destrukce Keyboard s chybou reference neexistujícího objektu Log q destrukce Logu by měla následovat až po destrukcích ostatních singletonů q nebo aspoň poznat problém a slušně umřít

Singleton detekce mrtvé reference n Detekce destruovaného objektu q přidání statické proměnné, její nastavení v destruktoru class Singleton { public: static Singleton& instance() { if (!instance) { if (destroyed) throw...; else create(); return *instance; private: static void create() { static Singleton inst; instance = &inst; Singleton() {... Singleton(const Singleton&); Singleton& operator=(const Singleton&); ~Singleton() { destroyed = true; instance = NULL; static bool destroyed; static Singleton* instance; ; Singleton* Singleton::instance = 0; bool Singleton::destroyed = false; detekce problému inicializace přesunuta do privátní metody nastavení zrušení příznak zrušení

Singleton Fénix n Detekce někdy nestačí - nutnost přístupu k singletonu kdykoliv q idea: bájný pták Fénix vstane ze svého popela q znovuvytvoření při detekci zrušeného objektu q příklad KDL - Keyboard a Display obyčejné singletony, Log Fénix q C++: paměť statických objektů zůstane alokována až do konce běhu programu q problém: stav starého mrtvého Singletonu je navždy ztracen class Singleton {... void KillPhoenix(); ; void Singleton::OnDeadRef() { Create(); new(instance) Singleton; atexit(killphoenix); destroyed = false; void Singleton::KillPhoenix() { instance->~singleton(); zbytek třídy nezměněn při detekci zrušení se uloží reference na paměť zrušeného objektu placement new zavolání konstruktoru na daném místě registrace destruktoru fénixu explicitní zavolání destruktoru nelze delete!

Singleton dlouhověkost n Problémy Fénixe q ztráta stavu, uložení, uzavření,... q Nejasnost C++ standardů ohledně funkce atexit() n Singleton s dlouhověkostí q při vytváření singletonu priorita destrukce q KDL Log bude mít větší dlouhověkost q explicitní mechanismus destrukce objektů n nelze použít destrukci řízenou kompilátorem - pouze dynamické objekty class SomeSingleton {... ; class SomeClass {... ; SomeClass* pglobalobject(new SomeClass); template <typename T> void SetLongevity(T* pdynobj, int longevity); int main() { SetLongevity(&SomeSingle().Inst(), 5); SetLongevity(pGlobalObject, 6);... mechanismus by měl fungovat na jakékoliv (dynamické) objekty šablona pro nastavování dlouhověkosti prioritní fronta na zabití po ukončení programu se objekty destruují v tomto pořadí

Singleton implementace dlouhověkosti n Prioritní fronta q při stejných prioritách se chová jako zásobník n C++ pravidlo: dříve inicializované objekty se destruují později q čeho to bude fronta? n neexistuje společný předek, registrační funkce je šablona n ukazatel na abstraktního předka šablon obsahujících ukazatel na objekt LifeTimeTracker virtual ~LifeTimeTracker() longevity virtuální držák virtuální destruktor šablona instanciována a objekt vytvořen šablonou SetLongevity ConcreteLTT<T> ~ConcreteLTT() T ~T() delete obj;

Singleton implementace dlouhověkosti class LifetimeTracker { public: LifetimeTracker(unsigned int x): longevity(x) { virtual ~LifetimeTracker() = 0; friend inline bool Compare( unsigned int longevity, const LifetimeTracker* p) { return p->longevity_ > longevity; private: unsigned int longevity; ; inline LifetimeTracker::~LifetimeTracker() { typedef LifetimeTracker** TrackerArray; extern TrackerArray pta; extern unsigned int elements; template <typename T> struct Deleter { static void Delete(T* pobj) { delete pobj; ; Bylo dříve vejce nebo slepice? n TrackerArray se musí chovat jako Singleton n čímžpádem ale trpí všemi jeho problémy virtuální držák umí zabíjet...... a porovnávat stáří vlastní fronta na zabití způsob zabití defaultně delete lze i free,...

Singleton multithreading n Vícevláknové prostředí q samo o sobě není pokryté standardy n platformově závislé knihovny Singleton instance() { if (instance == null) { instance = new Singleton(); return instance; sem se dostanou obě vlákna dva Singleton objekty M n Ochrana mutexem Singleton instance() { synchronized(this) { if (!instance) { instance = new Singleton(); return *instance; konstruktor objektu Lock zamkne destruktor odemkne q velmi neefektivní zamykání při každém přístupu

Singleton Double-Checked Locking n Double-Checked Locking Pattern q Doug Schmidt & Tim Harrison, C++ Report 1996 Singleton instance() { if (instance == null) { synchronized(this) { if (instance == null) { instance = new Singleton(); return instance; test inicializace sem se může dostat víc vláken odsud už jen jedno vlákno zde mi to už nikdo nezmění n Už je to konečně správně? q C++ není! q víc vláken norma nezaručuje vůbec nic q speciálně multi- a vícejaderné procesory n zápisy a čtení různých vláken nemusí být sekvenční q řešení: n platformově závislá synchronizační primitiva n memory barriers,...

Singleton kategorizace n Dělení z hlediska vytvoření q dynamické (operátor new, malloc) q statické (Meyers singleton) n Dělení z hlediska životnosti (lifetime) q Ostrichovo řešení (Leaking singleton) q životnost určená kompilátorem (Meyers singleton) q Fénix singleton q dlouhověkost (singleton with longevity) n Dělení z hlediska použití ve vláknech q jednovláknové bez synchronizace q thread safe s platformově závislou synchronizací

Singleton obecná implementace n Politiky (Policy classes) q mnoho kombinací možností implementace q šablona s možností vlastních voleb template < class T, template <class> class CreationPolicy = CreateUsingNew, template <class> class LifetimePolicy = DefaultLifetime, template <class> class ThreadingModel = SingleThreaded > class SingletonHolder {... ; class KeyboardImpl {... ; class LogImpl {... ; inline unsigned int GetLongevity(KeyboardImpl*) { return 1; inline unsigned int GetLongevity(LogImpl*) { return 2; typedef SingletonHolder<KeyboardImpl, SingletonWithLongevity> Keyboard; typedef SingletonHolder<LogImpl, SingletonWithLongevity> Log; n Alexandrescu: Modern C++ Design q knihovna Loki (@SourceForge)

Singleton implementace dědičnosti #include <iostream> template<typename T> class Base { public: static T &instance() { static T inst; return inst; virtual void echo () = 0; protected: Base() { virtual ~Base() { private: Base(const Base &); Base& operator=(const Base &); ; class Derived: public Base<Derived> { friend class Base<Derived>; public: void echo () { std::cout << I m Derived" << std::endl; protected: Derived() { virtual ~Derived() { ; int main(int argc, char **argv) { Derived &derived = Derived::instance(); derived.echo(); Dědičnost implementována pomocí šablon Možnost šablonování metody instance(), místo třídy Možnost vytváření abstrakních metod Třída Base<Derived> musí být náš friend (voláni konstruktoru ze statické metody instance()). Jednoduché použití

Singleton implementace C# using System; public abstract class DataProvider { static DataProvider instance = makeprovider(); public static DataProvider Instance { get { return instance; // nested classes can call private members private DataProvider() { public abstract void Connect(); static DataProvider makeprovider() { // Use Oracle on a Sunday, SQL Server otherwise if (DateTime.Now.DayOfWeek==DayOfWeek.Sunday) { return new OracleProvider(); else { return new SqlServerProvider(); Dědičnost implementována omocí šablon // There s no need to make the constructors // for the nested types non-public, as the classes // themselves are private to DataProvider. class OracleProvider : DataProvider { public override void Connect() { Console.WriteLine ( Connecting to Oracle ); class SqlServerProvider : DataProvider { public override void Connect() { Console.WriteLine ( Connecting to SQL Server);

Singleton související návrhové vzory n Možné použití q zjednodušení stavu aplikace - zajištění pouze jedné instance nějakého objektu q řízení přístupu do DB, tiskových zdrojů n omezení plýtvaní zdrojů (lze přidělit existující spojení) n možnost regulovat počty, frekvence přístupů n přidělení spojení s vhodnými právy n Související NV q Abstract Factory, Builder, Prototype n častá implementace pomocí singletonu q Facade n v případě potřeby pouze jednoho vstup do systému q State n stavové objekty jsou často Singletony

Singleton shrnutí n Dělení z hlediska vytvoření q dynamické (operátor new, malloc) n destruktor se nezavolá q statické (Meyers singleton) n funkce vracející referenci na statický objekt n Životnost (lifetime) q Ostrichovo řešení (Leaking singleton) n resource, memory leaks q killer n obalení ukazatele třídou starající se o destrukci q životnost určená kompilátorem (Meyers singleton) n destrukce v pořadí podle LIFO q detekce mrtvé reference n při detekci zrušeného objektu výjimka q Fénix singleton n po zrušení objektu jeho znovuvytvoření q dlouhověkost (singleton with longevity) n specifikace pořadí destrukcí n Threading model q jednovláknové n bez synchronizace q Double-checked locking n problémy se synchronizací platformě závislé pretty simple pattern J

Konec n Děkujeme za pozornost.