{"id":11495,"date":"2021-08-30T10:51:11","date_gmt":"2021-08-30T08:51:11","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=11495"},"modified":"2023-08-23T10:56:30","modified_gmt":"2023-08-23T08:56:30","slug":"pamiec-transakcyjna","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/pamiec-transakcyjna\/","title":{"rendered":"Pami\u0119\u0107 transakcyjna"},"content":{"rendered":"\n<p>Tworz\u0105c aplikacje pracuj\u0105ce w systemach wsp\u00f3\u0142bie\u017cnych, jak i rozproszonych, ka\u017cdy programista wcze\u015bniej czy p\u00f3\u017aniej stanie przed <strong>problemem synchronizacji dost\u0119pu w\u0105tk\u00f3w lub proces\u00f3w do obszaru zasob\u00f3w wsp\u00f3\u0142dzielonych<\/strong>, zw\u0142aszcza pami\u0119ci \u2013 czy to w celu komunikacji mi\u0119dzy procesami, czy w celu odczytu lub modyfikacji wsp\u00f3\u0142dzielonych danych. <\/p>\n\n\n\n<p>\u017b\u0105danie dost\u0119pu do danych mo\u017ce nast\u0105pi\u0107 jednocze\u015bnie w kilku w\u0105tkach, co wprowadza problem rywalizacji o zasoby. Jednak\u017ce, ka\u017cdy z w\u0105tk\u00f3w wymaga wy\u0142\u0105cznego dost\u0119pu do zasobu na czas wykonania kompletnej operacji. Sytuacja taka wymusza synchronizacj\u0119 dost\u0119pu do zasob\u00f3w przez w\u0105tki, tak aby z jednej strony wykluczy\u0107 modyfikowanie wsp\u00f3lnych zasob\u00f3w jednocze\u015bnie przez kilka w\u0105tk\u00f3w, a z drugiej strony zagwarantowa\u0107 pe\u0142n\u0105 wsp\u00f3\u0142bie\u017cno\u015b\u0107 i zniwelowa\u0107 mo\u017cliwy efekt \u201ezag\u0142odzenia\u201d w\u0105tku czy \u201ewy\u015bcigu szczur\u00f3w\u201d.<\/p>\n\n\n\n<p>Problemy te najcz\u0119\u015bciej rozwi\u0105zuje si\u0119 poprzez zastosowanie mechanizmu blokad, atomizacji, zamk\u00f3w itp. Ka\u017cdy ze sposob\u00f3w ma swoje wady i zalety. Cech\u0105 wsp\u00f3ln\u0105 tych rozwi\u0105za\u0144 jest to, \u017ce to programista musi zadba\u0107 o to, aby wra\u017cliwy fragment kodu by\u0142 w miar\u0119 mo\u017cliwo\u015bci w jednym miejscu (sekcja krytyczna), na\u0142o\u017cy\u0107 i zdj\u0105\u0107 odpowiednie muteksy, obs\u0142u\u017cy\u0107 sytuacje wyj\u0105tkowe i jednocze\u015bnie zagwarantowa\u0107 wsp\u00f3\u0142bie\u017cno\u015b\u0107.<\/p>\n\n\n\n<p>Rozpatrzmy bardzo prost\u0105 funkcj\u0119 zamieniaj\u0105c\u0105 dwie zmienne:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nvoid swap(int&amp;amp; x, int&amp;amp; y);\n<\/pre><\/div>\n\n\n<p>W wersji bez wsp\u00f3\u0142bie\u017cno\u015bci jest bardzo prosta:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nvoid swap(int&amp;amp; x, int&amp;amp; y){\nint tmp=x;\nx=y;\ny=tmp;\n}\n<\/pre><\/div>\n\n\n<p>Niestety przy zastosowaniu jej w wersji wsp\u00f3\u0142bie\u017cnej, mamy problem, gdy\u017c nie mamy gwarancji, \u017ce inny w\u0105tek nie zmieni\u0142 np. warto\u015bci zmiennej x pomi\u0119dzy przepisaniem jej do tmp a przypisaniem do y. W takiej sytuacji rozwi\u0105zanie wsp\u00f3\u0142bie\u017cne wygl\u0105da\u0142oby na przyk\u0142ad tak:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nvoid swap(int&amp;amp; x, int&amp;amp; y){\nmutex.lock();\nint tmp=x;\nx=y;\ny=tmp;\nmutex.unlock();\n}\n<\/pre><\/div>\n\n\n<p>Chocia\u017c bezpieczniejsze by\u0142oby np.:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nvoid swap(int&amp;amp; x, int&amp;amp; y){\nstd::lock_guard&amp;lt;:mutex&gt; lock(mutex);\nint tmp=x;\nx=y;\ny=tmp;\n}\n<\/pre><\/div>\n\n\n<p>Jeszcze wi\u0119ksze problemy wyst\u0105pi\u0105, gdy obie zmienne b\u0119d\u0105 pochodzi\u0142y z odr\u0119bnych blok\u00f3w lub, w przypadku system\u00f3w rozproszonych, gdy b\u0119d\u0105 przechowywane na r\u00f3\u017cnych w\u0119z\u0142ach. Nale\u017cy w\u00f3wczas zwi\u0119kszy\u0107 liczb\u0119 muteks\u00f3w i coraz bardziej komplikowa\u0107 kod wydawa\u0142oby si\u0119 prostej funkcji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>STM \u2013 Software Transactional Memory<\/strong><\/h2>\n\n\n\n<p>Aby odci\u0105\u017cy\u0107 programist\u0119 od pilnowania tych problem\u00f3w, upro\u015bci\u0107 kod i da\u0107 pewny w zachowaniu mechanizm ochronny, wprowadzono ide\u0119 zaczerpni\u0119t\u0105 z baz danych, czyli transakcje. <strong>Idea jest taka, \u017ce tworzymy jeden blok operacji modyfikuj\u0105cych dane wsp\u00f3\u0142dzielone jako jedn\u0105 transakcj\u0119, przy czym wszystkie instrukcje w transakcji musz\u0105 si\u0119 wykona\u0107 z sukcesem albo nie wykona si\u0119 \u017cadna<\/strong> (j.n. niepodzielno\u015b\u0107 transakcji \u2013 atomowo\u015b\u0107).<\/p>\n\n\n\n<p>Ka\u017cda transakcja musi spe\u0142nia\u0107 cztery warunki \u2013 jest to tzw. <strong>w\u0142asno\u015b\u0107 ACID<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>A<\/strong>tomicity (niepodzielno\u015b\u0107) \u2013 transakcja musi zosta\u0107 wykonana w ca\u0142o\u015bci lub wcale,<\/li>\n\n\n\n<li><strong>C<\/strong>onsistency (sp\u00f3jno\u015b\u0107) \u2013 po wykonaniu transakcji system pozostanie sp\u00f3jny, czyli nie zostan\u0105 naruszone jego zasady integralno\u015bci,<\/li>\n\n\n\n<li><strong>I<\/strong>solation (izolacja) \u2013 je\u015bli dwie transakcje wykonywane s\u0105 wsp\u00f3\u0142bie\u017cnie, to zwykle nie widz\u0105 wprowadzanych przez siebie zmian,<\/li>\n\n\n\n<li><strong>D<\/strong>urability (sta\u0142o\u015b\u0107) \u2013 oznacza, \u017ce system potrafi si\u0119 uruchomi\u0107 i udost\u0119pni\u0107 sp\u00f3jne, nienaruszone i aktualne dane zapisane w ramach zatwierdzonych transakcji w wypadku wyst\u0105pienia sytuacji wyj\u0105tkowej.<\/li>\n<\/ul>\n\n\n\n<p>Idea ta, u\u017cyta w j\u0119zyku programowania do zarz\u0105dzania danymi wsp\u00f3\u0142dzielonymi, to w\u0142a\u015bnie <strong>STM \u2013 Software Transactional Memory<\/strong>. Nale\u017cy tu doda\u0107, \u017ce istniej\u0105 podej\u015bcia wprowadzaj\u0105ce t\u0119 ide\u0119 w hardware np. rozszerzenia TSX w niekt\u00f3rych procesorach Intela.<\/p>\n\n\n\n<p>Podstawy STM stworzyli Nir Shavit i Dan Touitou w 1995 roku. Niemniej ze wzgl\u0119du na problemy implementacyjne (wycofywanie i ponawianie transakcji, obs\u0142uga wyj\u0105tk\u00f3w itd.) pierwsze wdro\u017cenia nast\u0105pi\u0142y dosy\u0107 p\u00f3\u017ano. Co ciekawe, najwcze\u015bniejszym wdro\u017ceniem by\u0142a adaptacja Erlangowej Mnesii opracowana przez Ericsson, kt\u00f3ra, pomimo \u017ce jej podstawow\u0105 funkcjonalno\u015bci\u0105 jest rozproszony, transakcyjny DBMS, spe\u0142nia r\u00f3wnie\u017c wymagania i oczekiwania STM. W 2005 roku Tim Harris, Simon Marlow, Simon Peyton Jones i Maurice Herlihy opisali system STM zbudowany na Concurrent Haskell, Umo\u017cliwia on u\u0142o\u017cenie dowolnych operacji atomowych w wi\u0119ksze operacje atomowe, co jest niemo\u017cliwe z programowaniem blokuj\u0105cym.<\/p>\n\n\n\n<p>Inne implementacje to np.: ScalaSTM, JVSTM (Java), Concurent Ruby, Pugs(Perl), PyPy STM (Python). W przypadku j\u0119zyka C\/C++ implementacje STM to TintSTM, Intel STM Compiler, LibLTX oraz wdro\u017cenie w GCC++ (od v. 4.7, kt\u00f3re zdaje si\u0119 by\u0107 pewn\u0105 baz\u0105 dla standardu C++20). Dok\u0142adniejszy opis idei STM mo\u017cna znale\u017a\u0107 w opracowaniu [1] oraz [5].<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Zastosowanie praktyczne: C++<\/strong><\/h2>\n\n\n\n<p>Przypomnijmy sobie typow\u0105 transakcj\u0119 SQL-ow\u0105:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nBEGIN TRANSACTION\n\/\/ci\u0105g instrukcji SQL\nINSERT INTO ....\n.....\nCOMMIT TRANSACTION\n<\/pre><\/div>\n\n\n<p>Tak skonstruowany ci\u0105g operacji na bazie zostanie wykonany w ca\u0142o\u015bci, gdy powiod\u0105 si\u0119 wszystkie operacje i zostanie z powodzeniem wykonany commit. W przeciwnym wypadku zostanie wywo\u0142any rollback i wszystkie zmiany cofn\u0105 si\u0119. Dok\u0142adnie to samo piszemy w przypadku nadzorowania operacjami nad pami\u0119ci\u0105 wsp\u00f3\u0142dzielon\u0105 w STM.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\n__transaction_atomic{\noperacja1();\noperacja2();\n}\n<\/pre><\/div>\n\n\n<p>Mamy tu blok operacji na pami\u0119ci wsp\u00f3\u0142dzielonej nadzorowany przez STM (sk\u0142adnia gcc). Ca\u0142y blok zostanie zako\u0144czony, a ewentualne modyfikacje zapisane, gdy wykonanie wszystkich operacji zostanie zwie\u0144czone sukcesem. W przeciwnym wypadku ca\u0142o\u015b\u0107 zostaje wycofana do stanu pocz\u0105tkowego i ponownie wykonana.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Trudno\u015bci implementacyjne<\/strong><\/h2>\n\n\n\n<p>Jedn\u0105 z trudno\u015bci implementacyjnych stanowi to, <strong>w jaki spos\u00f3b przywr\u00f3ci\u0107 stan pocz\u0105tkowy<\/strong>. Mamy kilka mo\u017cliwo\u015bci. Mo\u017cemy albo gdzie\u015b go przechowywa\u0107 (dodatkowe kopiowanie), stworzy\u0107 metod\u0119 wsteczn\u0105 (ale to \u0142amie zasad\u0119 izolacji) albo jak w TSQL \u2013 tworzy\u0107 logi.<\/p>\n\n\n\n<p>Nast\u0119pn\u0105 otwart\u0105 kwesti\u0105 pozostaje, <strong>jak wykrywa\u0107 ewentualne konflikty czy inne czynniki nakazuj\u0105ce wycofanie transakcji<\/strong>.<\/p>\n\n\n\n<p>Istniej\u0105 dwa podej\u015bcia do sterowania wsp\u00f3\u0142bie\u017cno\u015bci\u0105 transakcji: optymistyczne i pesymistyczne. Optymistyczne oznacza, \u017ce transakcje wykonywane s\u0105 niezale\u017cnie, a ewentualne konflikty, z powodu modyfikacji tych samych danych wsp\u00f3\u0142dzielonych, wykrywane s\u0105 podczas zatwierdzania transakcji. W przypadku ich wyst\u0105pienia transakcja jest wycofywana, czyli nast\u0119puje przywr\u00f3cenie obiekt\u00f3w do stanu sprzed wykonania transakcji. Transakcja jest nast\u0119pnie wykonywana ponownie, co mo\u017ce powodowa\u0107 wielokrotne wykonanie operacji nieodwracalnych, kt\u00f3re obejmuje ta transakcja.<\/p>\n\n\n\n<p>W podej\u015bciu pesymistycznym transakcje oczekuj\u0105 na dost\u0119p do wszystkich wsp\u00f3\u0142dzielonych obiekt\u00f3w i gdy warunek ten jest spe\u0142niony, jest wykonywana. Skutkuje to brakiem konflikt\u00f3w spowodowanych przez jednoczesny dost\u0119p do zasob\u00f3w. W efekcie transakcje nie musz\u0105 by\u0107 wycofywane i nie wyst\u0119puje problem z operacjami nieodwracalnymi.<\/p>\n\n\n\n<p>Jak wida\u0107, implementacja nie jest prosta, st\u0105d prace nad wdro\u017ceniem STM (podej\u015bcia optymistycznego) do standardu C++ trwaj\u0105 ju\u017c od 2012 roku i dopiero teraz maj\u0105 szanse zosta\u0107 zako\u0144czone (cho\u0107 pierwotnie mia\u0142y zosta\u0107 wprowadzone w standardzie C++17).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Bloki do obs\u0142ugi pami\u0119ci transakcyjnej<\/strong><\/h2>\n\n\n\n<p>W wyniku wieloletnich prac oraz uwzgl\u0119dniaj\u0105c istniej\u0105ce rozwi\u0105zania, postanowiono wprowadzi\u0107 dwa rodzaje blok\u00f3w do obs\u0142ugi pami\u0119ci transakcyjnej: bloki zsynchronizowane i bloki atomowe:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>bloki zsynchronizowane<\/strong> zachowuj\u0105 si\u0119 tak, jakby wszystkie bloki by\u0142y chronione przez jeden globalny muteks rekursywny,<\/li>\n<\/ul>\n\n\n\n<p>Bloki zsynchronizowane deklarowane s\u0105 nast\u0119puj\u0105co:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nsynchronized { kod_bloku }\n<\/pre><\/div>\n\n\n<p>Maj\u0105 one na celu rozwi\u0105za\u0107 niekt\u00f3re trudno\u015bci wi\u0105\u017c\u0105ce si\u0119 z u\u017cywaniem muteks\u00f3w do synchronizowania dost\u0119pu do pami\u0119ci oraz upro\u015bci\u0107 ten dost\u0119p. Daj\u0105 wi\u0119kszy poziom abstrakcji i wi\u0119ksz\u0105 elastyczno\u015b\u0107. Nie s\u0105 one transakcjami i dlatego mog\u0105 wywo\u0142ywa\u0107 funkcje niebezpieczne transakcyjnie oraz mog\u0105 by\u0107 zagnie\u017cd\u017cone. Opuszczenie zsynchronizowanego bloku (niezale\u017cnie od tego, czy poprzez dotarcie do ko\u0144ca, opuszczenie czy poprzez wywo\u0142anie wyj\u0105tku) powoduje synchronizacj\u0119 z nast\u0119pnym blokiem. <\/p>\n\n\n\n<p>Nie mniej jednak zalecane jest zmniejszanie wielko\u015bci i ilo\u015bci blok\u00f3w zsynchronizowanych, ze wzgl\u0119du na wydajno\u015b\u0107 oraz mo\u017cliwo\u015b\u0107 spekulatywnego wykonania operacji, takich jak I\/O. Natomiast, by\u0107 mo\u017ce, w implementacjach zsynchronizowanych, uwzgl\u0119dnione zostanie wykorzystanie sprz\u0119towej obs\u0142ugi pami\u0119ci transakcyjnej. Na bloki zsynchronizowane na\u0142o\u017cono kilka ogranicze\u0144. Przede wszystkim zabronione zosta\u0142o wchodzenie do cia\u0142a bloku zsynchronizowanego poprzez <strong>goto<\/strong> lub <strong>switch<\/strong>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>bloki atomowe<\/strong> (nazywane r\u00f3wnie\u017c transakcjami atomowymi lub po prostu transakcjami) sprawiaj\u0105 wra\u017cenie, \u017ce s\u0105 jedn\u0105 operacj\u0105 atomow\u0105, a nie zsynchronizowanym blokiem (chyba \u017ce blok atomowy jest wykonywany w zsynchronizowanym bloku).<\/li>\n<\/ul>\n\n\n\n<p>Transakcje atomowe zosta\u0142y podzielone na trzy formy, deklarowane nast\u0119puj\u0105co:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\natomic_noexcept { kod_bloku }\natomic_commit { kod_bloku }\natomic_cancel { kod_bloku }\n<\/pre><\/div>\n\n\n<p>S\u0142owo kluczowe nast\u0119puj\u0105ce po atomic to specyfikator wyj\u0105tku bloku atomowego. Okre\u015bla zachowanie w sytuacjach wyj\u0105tkowych:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>noexcept<\/strong>: je\u015bli zostanie zg\u0142oszony wyj\u0105tek, wywo\u0142ywane jest std::abort<\/li>\n\n\n\n<li><strong>commit<\/strong>: je\u015bli zostanie zg\u0142oszony wyj\u0105tek, transakcja zostanie zatwierdzona normalnie<\/li>\n\n\n\n<li><strong>cancel<\/strong>: je\u015bli zostanie zg\u0142oszony wyj\u0105tek, wywo\u0142ywane jest std::abort, chyba \u017ce wyj\u0105tek jest jednym z wyj\u0105tk\u00f3w u\u017cywanych do anulowania transakcji, w kt\u00f3rym to przypadku transakcja jest anulowana: warto\u015bci wszystkich lokalizacji pami\u0119ci w programie, kt\u00f3re zosta\u0142y zmodyfikowane przez efekty uboczne operacji bloku atomowego s\u0105 przywracane do warto\u015bci, kt\u00f3re mia\u0142y w momencie uruchomienia bloku atomowego, a wyj\u0105tek kontynuuje rozwijanie stosu.<\/li>\n<\/ul>\n\n\n\n<p><strong>Wyj\u0105tki u\u017cywane do anulowania dla transakcji:<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nstd::bad_alloc, std::bad_array_new_length, std::bad_cast, std::bad_typeid, \nstd::bad_exception, std::exception, std::tx_exception.\n<\/pre><\/div>\n\n\n<p>Zestaw typ\u00f3w wyj\u0105tk\u00f3w bezpiecznych ca\u0142y czas ulega modyfikacji i najlepiej sprawdzi\u0107 je w dokumentacji [2], [4]. Kod w tre\u015bci transakcji musi by\u0107 bezpieczny pod wzgl\u0119dem transakcji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Jak zapewni\u0107 bezpiecze\u0144stwo transakcyjne?<\/strong><\/h2>\n\n\n\n<p><strong>Kod jest transakcyjnie niebezpieczny<\/strong>, je\u015bli:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>zawiera inicjalizacj\u0119, przypisanie lub odczyt z obiektu zmiennego,<\/li>\n\n\n\n<li>zawiera deklaracj\u0119 <strong>asm<\/strong>,<\/li>\n\n\n\n<li>zawiera wywo\u0142anie funkcji niebezpiecznej transakcji lub wska\u017anika funkcji, kt\u00f3ry nie jest transakcj\u0105 bezpieczn\u0105,<\/li>\n\n\n\n<li>zawiera alokacj\u0119 i dealokacj\u0119 pami\u0119ci (odwo\u0142anie do systemu operacyjnego), aczkolwiek to ograniczenie mo\u017ce zosta\u0107 usuni\u0119te w wersji finalnej standardu.<\/li>\n<\/ul>\n\n\n\n<p>Poza tym zabronione jest wej\u015bcie do bloku atomowego przy u\u017cyciu <strong>goto<\/strong> lub <strong>switch<\/strong>, synchronizacja przy pomocy blokad i obiekt\u00f3w atomowych oraz u\u017cywanie funkcji niebezpiecznych transakcyjnie. Dodatkowo blok\u00f3w transakcyjnych nie wolno zagnie\u017cd\u017ca\u0107. Wszystkie warunki okre\u015blaj\u0105ce co jest bezpieczne transakcyjnie, a co nie, precyzyjnie opisano w pozycjach [2], [3], [4].<\/p>\n\n\n\n<p>Standard wprowadza r\u00f3wnie\u017c dodatkowe identyfikatory specjalnego znaczenia <strong>transaction_safe<\/strong> dla okre\u015blenia explicite funkcji\/metod, kt\u00f3re s\u0105 transakcyjnie bezpieczne, <strong>transaction_safe_dynamic<\/strong> i <strong>transaction_safe_noinherit<\/strong> dla funkcji wirtualnych oraz <strong>transaction_unsafe<\/strong> dla okre\u015blenia funkcji transakcyjnie niebezpiecznych. Wykorzystywane r\u00f3wnie\u017c przy tworzeniu szablon\u00f3w klas\/funkcji bezpiecznych transakcyjnie.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nstruct A {\nvirtual void f1() transaction_safe;\nvirtual ~A()transaction_safe_noinherit;\nvirtual f2() transaction_safe_dynamic;\n};\n\ntemplate {\nvoid fun1(T) transaction_safe; \/\/bezpieczna transakcyjnie\nvoid fun2(T) transaction_unsafe; \/\/nie bezpieczna transakcyjnie\n}\n<\/pre><\/div>\n\n\n<p>Dodano r\u00f3wnie\u017c nowy typ wyj\u0105tku <strong>tx_exception<\/strong>, kt\u00f3ry powinien by\u0107 u\u017cywany do anulowania i wycofywania transakcji atomowej w bloku <strong>atomic_cancel<\/strong>.<\/p>\n\n\n\n<p>Nadal natomiast trwaj\u0105 prace zwi\u0105zane z destruktorami i destruktorami dla typ\u00f3w wyj\u0105tk\u00f3w, funkcjami wirtualnymi czy parametrami wska\u017anika funkcji do funkcji (np. qsort). Istnieje kilka koncepcji rozwi\u0105zania istniej\u0105cych problem\u00f3w, lecz nie wiadomo, jakie rozwi\u0105zanie zostanie ostatecznie zaakceptowane. [2]. [3], [4].<\/p>\n\n\n\n<p>Pewn\u0105, ale nadal niezatwierdzon\u0105 koncepcj\u0105 jest wprowadzenie domen dla zsynchronizowanych blok\u00f3w. Sk\u0142adniowo wygl\u0105da\u0142oby to tak:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nsynchronized (domena) { kod_bloku }\n<\/pre><\/div>\n\n\n<p>Je\u015bli ka\u017cdy zsynchronizowany blok ma dok\u0142adnie jedn\u0105 domen\u0119 (i system nie rozpoznaje \u017cadnej relacji mi\u0119dzy domenami), to jest logicznie r\u00f3wnowa\u017cne z posiadaniem r\u00f3\u017cnych muteks\u00f3w dla ka\u017cdej domeny. Jednak\u017ce to poj\u0119cie jest bardziej og\u00f3lne ni\u017c muteksy w przypadku, gdy zsynchronizowane bloki mog\u0105 okre\u015bla\u0107 wiele domen. Wprowadza to wiele trudno\u015bci implementacyjnych, wi\u0119c w tej chwili jest ca\u0142kowicie na etapie koncepcyjnym.<\/p>\n\n\n\n<p>Po zapoznaniu si\u0119 z tymi informacjami mo\u017cemy wr\u00f3ci\u0107 do naszej funkcji <strong>swap<\/strong> i pokaza\u0107, jak wygl\u0105da\u0142aby jej implementacja w oparciu o STM.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nvoid swap(int&amp;amp; x, int&amp;amp; y){\natomic_commit{\nint tmp=x;\nx=y;\ny=tmp;\n}\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Nadzieje na wdro\u017cenie<\/strong><\/h2>\n\n\n\n<p>Niestety wdra\u017canie STM w standardzie C++ przebiega wyj\u0105tkowo powoli, co jest z jednej strony zwi\u0105zane zw\u0142aszcza z problemami zachowania sp\u00f3jno\u015bci przy wycofywaniu transakcji w przypadku niepowodzenia, a z drugiej dziwne wobec coraz wi\u0119kszego wsparcia dla pami\u0119ci transakcyjnej w nowych procesorach. W zwi\u0105zku z tymi problemami powsta\u0142a inicjatywa \u201eTransactional Memory Lite Support in C++\u201d. <\/p>\n\n\n\n<p>Jest to naj\u015bwie\u017csze podej\u015bcie do pami\u0119ci transakcyjnej opieraj\u0105ce si\u0119 na zmniejszeniu wymaga\u0144 wobec STM, wykorzystaniu algorytm\u00f3w programowej pami\u0119ci TM, a tak\u017ce sprz\u0119tow\u0105 i hybrydow\u0105 pami\u0119\u0107 TM oraz serializacj\u0119 transakcji na wkl\u0119s\u0142ej blokadzie mutex. Proponuje ona sk\u0142adni\u0119<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\natomic\ndo {\n...\n}\n<\/pre><\/div>\n\n\n<p>Za\u0142o\u017ceniem <strong>podej\u015bcia \u201elite\u201d<\/strong> jest gwarancja, \u017ce transakcje b\u0119d\u0105 wygl\u0105da\u0107 niepodzielnie w stosunku do innych transakcji.<br>Konkretnie:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Dwie transakcje powoduj\u0105 konflikt, je\u015bli maj\u0105 dost\u0119p do tej samej lokalizacji i co najmniej jedna z nich zapisuje t\u0119 lokalizacj\u0119.<\/li>\n\n\n\n<li>Je\u015bli transakcje A i B s\u0105 w konflikcie, to albo koniec mi\u0119dzy w\u0105tkiem A nast\u0119puje \u2013 przed pocz\u0105tkiem B, albo koniec mi\u0119dzy w\u0105tkiem B \u2013 przed pocz\u0105tkiem A.<\/li>\n<\/ol>\n\n\n\n<p>Propozycj\u0105 wersji \u201elite\u201d s\u0105 r\u00f3wnie\u017c alternatywy syntaktyczne i implementacje prototypowanie.<\/p>\n\n\n\n<p>Pierwsz\u0105 opcj\u0105 jest struktura wykonania oparta na lambdzie do uruchamiania transakcji. W tym frameworku programista \u017c\u0105da uruchomienia bloku kodu jako transakcji, umieszczaj\u0105c go w wyra\u017ceniu lambda i przekazuj\u0105c do specjalnej biblioteki TM.<\/p>\n\n\n\n<p>Zamiast atomic { &#8230; } , oczekujemy, \u017ce sk\u0142adnia b\u0119dzie wygl\u0105da\u0107 mniej wi\u0119cej tak:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nstd::tm_exec(&#x5B;&amp;amp;]{... });\n<\/pre><\/div>\n\n\n<p>Mocne strony tego podej\u015bcia to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>nie s\u0105 wymagane \u017cadne zmiany w interfejsie kompilatora,<\/li>\n\n\n\n<li>w przypadku system\u00f3w ze sprz\u0119tow\u0105 obs\u0142ug\u0105 TM mo\u017cliwe jest zaimplementowanie std::tm_exec w ca\u0142o\u015bci jako bibliotek\u0119: std::tm_exec mo\u017ce (1) rozpocz\u0105\u0107 transakcj\u0119 sprz\u0119tow\u0105, (2) wykona\u0107 lambd\u0119, a nast\u0119pnie (3) zatwierdzi\u0107 sprz\u0119t transakcj\u0119, wracaj\u0105c do ukrytej globalnej std::mutex w przypadku powtarzaj\u0105cego si\u0119 niepowodzenia,<\/li>\n\n\n\n<li>w przypadku system\u00f3w bez sprz\u0119towej obs\u0142ugi pami\u0119ci TM mo\u017cliwe jest zaimplementowanie std::tm_exec poprzez serializacj\u0119 wszystkich transakcji przy u\u017cyciu jednego nienazwanego globalnego std::mutex. Taka implementacja nie zapewni\u0142aby skalowalno\u015bci. Jednak w trosce o jak naj\u0142atwiejsze wdro\u017cenie TM nie s\u0105 wykluczane rozwi\u0105zania w pocz\u0105tkowej fazie TS,<\/li>\n\n\n\n<li>w przypadku system\u00f3w, kt\u00f3re chc\u0105 doda\u0107 obs\u0142ug\u0119 oprogramowania TM, lambda w naturalny spos\u00f3b umo\u017cliwia kompilatorowi przechwytywanie i dost\u0119p instrumentu do pami\u0119ci w zakresie lokalnym oraz do \u015bledzenia\/wykrywania nieprawid\u0142owych operacji, takich jak wywo\u0142ania funkcji poza jednostk\u0105 t\u0142umaczeniow\u0105, dost\u0119py do zmiennych volatile i atomowych itp.<\/li>\n<\/ul>\n\n\n\n<p>Inn\u0105 opcj\u0105 jest u\u017cycie idiomu <strong>R<\/strong>esource <strong>A<\/strong>cquisition <strong>I<\/strong>s <strong>I<\/strong>nitialization \u201epozyskiwanie zasob\u00f3w to inicjalizacja\u201d do oznaczania podmiot\u00f3w transakcyjnych. To znaczy zamiast pisa\u0107 atomic do { &#8230; }, programista napisa\u0142by:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\n{std::transaction_scope ts(); ... }\n<\/pre><\/div>\n\n\n<p>Wi\u0119kszo\u015b\u0107 zalet tego podej\u015bcia jest taka sama, jak w przypadku podej\u015bcia lambda. W szczeg\u00f3lno\u015bci:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>nie s\u0105 wymagane \u017cadne zmiany w interfejsie kompilatora,<\/li>\n\n\n\n<li>w przypadku system\u00f3w ze sprz\u0119tow\u0105 obs\u0142ug\u0105 pami\u0119ci TM oraz w systemach, kt\u00f3re decyduj\u0105 si\u0119 na serializacj\u0119 wszystkich transakcji w globalnym, nienazwanym muteks, wsparcie TM mo\u017cna osi\u0105gn\u0105\u0107 w ca\u0142o\u015bci w bibliotece. Rozpocz\u0119cie transakcji odbywa si\u0119 w konstruktorze std::transaction_scope. Zatwierdzanie transakcji odbywa si\u0119 w destruktorze.<\/li>\n<\/ul>\n\n\n\n<p>Ponadto unika si\u0119 dw\u00f3ch pierwszych s\u0142abo\u015bci podej\u015bcia lambda. To jest:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>nie ma \u017cadnych dodatkowych koszt\u00f3w zwi\u0105zanych z tworzeniem i zarz\u0105dzaniem lambd\u0105,<\/li>\n\n\n\n<li>dost\u0119pne s\u0105 wszystkie zmienne z zakresu nadrz\u0119dnego, nawet te (takie jak varargs) kt\u00f3rego nie mo\u017cna przechwyci\u0107 przez lambd\u0119.<\/li>\n<\/ul>\n\n\n\n<p>To podej\u015bcie jest dost\u0119pne w postaci wtyczki do LLVM. Znajdziesz tu r\u00f3wnie\u017c kod oraz szczeg\u00f3\u0142y realizacji.<\/p>\n\n\n\n<p>Poniewa\u017c wiele kwestii jest nadal otwartych, mog\u0105 nast\u0105pi\u0107 pewne r\u00f3\u017cnice pomi\u0119dzy zawartymi tu informacjami a wersj\u0105 ostateczn\u0105 standardu. Dlatego zach\u0119cam zainteresowanych do przegl\u0105dania statusu dokumentacji i post\u0119pu prac nad STM na <a href=\"http:\/\/www.open-std.org\/JTC1\/SC22\/WG21\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >stronach<\/a> po\u015bwi\u0119conych standardowi <a href=\"https:\/\/isocpp.org\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >C++<\/a>.<\/p>\n\n\n\n<p>Reasumuj\u0105c, na chwil\u0119 obecn\u0105 prace komitetu standaryzacyjnego nad wprowadzeniem STM zwolni\u0142y. Jest to dziwne, zw\u0142aszcza, \u017ce producenci procesor\u00f3w coraz bardziej wspieraj\u0105 w swoich nowych projektach sprz\u0119tow\u0105 TM. R\u00f3wnie\u017c tw\u00f3rcy innych j\u0119zyk\u00f3w, cho\u0107by Python czy Java, wdra\u017caj\u0105 ide\u0119 STM. \u201e\u015awiate\u0142kiem w tunelu\u201d jest inicjatywa LLVM. G\u0142\u00f3wna przyczyn\u0105 takiego stanu rzeczy s\u0105 przede wszystkim problemy z bezpiecznym wycofywaniem transakcji w przypadku niepowodzenia. Mam jednak nadziej\u0119, \u017ce w najbli\u017cszym czasie prace nad wdro\u017ceniem STM do standardu C++ rusz\u0105 z miejsca.<\/p>\n\n\n\n<p><strong>Literatura:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/pdfs.semanticscholar.org\/4758\/a69dd38d7a625d8a6b1994447eaf742e7305.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >\u201cTaxonomy for Transactional Memory Systems\u201d &#8211; Shweta Kulkarni i inni<\/a><\/li>\n\n\n\n<li>\u201cTransactional Memory Support for C++\u201d &#8211; Victor Luchangco i inni (<a href=\"http:\/\/open-std.org\/JTC1\/SC22\/WG21\/docs\/papers\/2013\/n3718.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >2013<\/a>, <a href=\"http:\/\/open-std.org\/JTC1\/SC22\/WG21\/docs\/papers\/2014\/n3919.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >2014<\/a>, <a href=\"http:\/\/open-std.org\/JTC1\/SC22\/WG21\/docs\/papers\/2014\/n3859.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >2014)<\/a><\/li>\n\n\n\n<li><a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2015\/n4513.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >\u201cWorking Draft Technical Specification for C++ Extensions for Transactional Memory\u201d \u2013 Michael Wong i inni<\/a><\/li>\n\n\n\n<li><a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2015\/n4514.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >\u201cTechnical Specification for C++ Extensions for Transactional Memory\u201d<\/a><\/li>\n\n\n\n<li><a href=\"http:\/\/open-std.org\/JTC1\/SC22\/WG21\/docs\/papers\/2021\/p1875r2.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >\u201cTransactional Memory Lite Support in C++\u201d<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.bscmsrc.eu\/sites\/default\/files\/interact11-milos_0.pdf\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >\u201cCompile time support for using Transactional Memory in C\/C++ applications\u201d &#8211; Milo\u0161 Milovanovi\u0107 i inni<\/a><\/li>\n\n\n\n<li>Standard ISO\/IEC TS 19841:2015<\/li>\n<\/ol>\n\n\n\n<p>***<\/p>\n\n\n\n<p>Je\u015bli interesujesz si\u0119 tematyk\u0105 C++, zajrzyj r\u00f3wnie\u017c <a href=\"https:\/\/sii.pl\/blog\/wyszukiwarka\/c%2B%2B\/\" target=\"_blank\" aria-label=\"do innych artyku\u0142\u00f3w naszych ekspert\u00f3w (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">do innych artyku\u0142\u00f3w naszych ekspert\u00f3w<\/a>. <\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;11495&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;3&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 3)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Pami\u0119\u0107 transakcyjna&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 3)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Tworz\u0105c aplikacje pracuj\u0105ce w systemach wsp\u00f3\u0142bie\u017cnych, jak i rozproszonych, ka\u017cdy programista wcze\u015bniej czy p\u00f3\u017aniej stanie przed problemem synchronizacji dost\u0119pu w\u0105tk\u00f3w &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/pamiec-transakcyjna\/\">Continued<\/a><\/p>\n","protected":false},"author":308,"featured_media":11507,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[1058,271,1112],"class_list":["post-11495","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-cpp","tag-memory","tag-programowanie-wielowatkowe"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/08\/Pami\u0119\u0107-transakcyjna-.png","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/11495"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/308"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=11495"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/11495\/revisions"}],"predecessor-version":[{"id":23782,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/11495\/revisions\/23782"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/11507"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=11495"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=11495"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=11495"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}