{"id":543,"date":"2019-02-05T14:35:23","date_gmt":"2019-02-05T13:35:23","guid":{"rendered":"https:\/\/www.kompikownia.pl\/?p=543"},"modified":"2019-02-09T16:11:51","modified_gmt":"2019-02-09T15:11:51","slug":"aplikacje-wielowatkowe-w-jezyku-c","status":"publish","type":"post","link":"https:\/\/www.kompikownia.pl\/index.php\/2019\/02\/05\/aplikacje-wielowatkowe-w-jezyku-c\/","title":{"rendered":"Aplikacje wielow\u0105tkowe w j\u0119zyku C++"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">9<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span>\n<p class=\"has-text-color has-headings-color\">Czy pisa\u0142e\u015b kiedy\u015b program, kt\u00f3ry potrzebowa\u0142 du\u017co mocy CPU? Zastanawia\u0142e\u015b si\u0119 dlaczego twoja aplikacja u\u017cywa maksymalnie jednego rdzenia, nawet je\u015bli masz ich kilka\/kilkana\u015bcie? Czy tworzy\u0142e\u015b kiedy\u015b program, kt\u00f3ra odczytywa\u0142 z dysku du\u017cy plik? I w tym momencie, w kt\u00f3rym ten plik by\u0142 odczytywany program nie reagowa\u0142 na polecenia u\u017cytkownika? No c\u00f3\u017c, jest to ca\u0142kowicie normalne zjawisko. Aby aplikacja potrafi\u0142a korzysta\u0107 z wielu rdzeni, musisz sprawi\u0107, aby wykonywa\u0142a si\u0119 w wielu w\u0105tkach. Dzisiaj nauczysz si\u0119, jak napisa\u0107 taki program w j\u0119zyku C++. Dowiesz si\u0119 tak\u017ce, jakie problemy pojawiaj\u0105 si\u0119, gdy tworzymy aplikacj\u0119 wielow\u0105tkow\u0105. No to do dzie\u0142a!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Czym jest proces? Czym jest w\u0105tek?<\/h2>\n\n\n\n<p class=\"has-text-color has-headings-color\">Aby\u015b dok\u0142adnie zrozumia\u0142 temat, musisz najpierw zrozumie\u0107 dwa podstawowe poj\u0119cia, kt\u00f3re pojawi\u0142y si\u0119 w tytule tego paragrafu. Ka\u017cdy program w systemie operacyjnym jest tzw. <strong>procesem<\/strong>.W systemie operacyjnym uruchomiona jest r\u00f3wnocze\u015bnie du\u017ca ilo\u015b\u0107 program\u00f3w. Nawet na komputerze jednordzeniowym mamy wra\u017cenie, \u017ce programy te pracuj\u0105 jednocze\u015bnie. Jak to si\u0119 dzieje, skoro procesor mo\u017ce wykonywa\u0107 jedynie jedno zadanie na raz? Ot\u00f3\u017c, procesor nie pracuje nad jednym programem ca\u0142y czas. Ka\u017cdy z proces\u00f3w istniej\u0105cych w systemie ma okazj\u0119 dosta\u0107 czas CPU. Procesor przydzielany jest na zmian\u0119 ka\u017cdemu z proces\u00f3w. Przydzia\u0142 ten zmienia si\u0119 co okre\u015blony, bardzo kr\u00f3tki czas. Dzi\u0119ki temu odnosimy wra\u017cenie \u017ce wszystkie aplikacje wykonuj\u0105 si\u0119 w tym samym momencie. <\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Wr\u00f3\u0107my do problemu ze wst\u0119pu. Na podstawie wy\u017cej napisanych s\u0142\u00f3w m\u00f3g\u0142by\u015b uwa\u017ca\u0107, \u017ce mo\u017cna napisa\u0107 po prostu dwa programy. Ot\u00f3\u017c, nie jest to takie proste. Ka\u017cdy proces otrzymuje w\u0142asn\u0105 przestrze\u0144 adresow\u0105 (czyli miejsce w pami\u0119ci RAM, w kt\u00f3rej mo\u017ce przechowywa\u0107 swoje zmienne). Istniej\u0105 sposoby komunikacji mi\u0119dzy dwoma r\u00f3\u017cnymi procesami. Jednak\u017ce, jest to czynno\u015b\u0107 skomplikowana. Istnieje inne rozwi\u0105zanie. S\u0105 nim: <strong>w\u0105tki.<\/strong><\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\"><strong>W\u0105tek&nbsp;<\/strong>niewiele r\u00f3\u017cni si\u0119 od procesu. Je\u015bli chodzi o przydzia\u0142 czasu procesora, traktowany jest zwykle identycznie jak zwyk\u0142y proces. Pomimo tego, jest jedna rzecz, kt\u00f3ra odr\u00f3\u017cnia te poj\u0119cia.<em>W\u0105tek&nbsp;dzia\u0142a&nbsp;w&nbsp;ramach&nbsp;przestrzeni&nbsp;adresowej&nbsp;procesu,&nbsp;kt\u00f3ry&nbsp;go&nbsp;utworzy\u0142.<\/em>Oznacza to, \u017ce w\u0105tek przechowuje swoje zmienne w tym samym obszarze pami\u0119ci RAM, kt\u00f3ry zosta\u0142 przydzielony procesowi, kt\u00f3ry go stworzy\u0142. W\u0105tek ma zatem dost\u0119p do zmiennych swojego &#8222;rodzica&#8221;. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tworzenie aplikacji wielow\u0105tkowej w j\u0119zyku C++<\/h2>\n\n\n\n<div class=\"important-everywhere\">\n  <div class=\"important-header\">\n  Wa\u017cne!!!\n  <\/div>\n  <div class=\"important-body\">\n  Aby\u015b m\u00f3g\u0142 skompilowa\u0107 umieszczone poni\u017cej programy na swoim komputerze, musisz<\/br>\n  w ustawieniach kompilatora wybra\u0107 flag\u0119 &#8211;std=c++14 <br>\n  Je\u015bli dostaniesz b\u0142\u0105d &#8222;undefined reference to pthread_create (&#8230;)&#8221; musisz w ustawieniach linkera doda\u0107 flag\u0119 -lpthread\n  <\/div>\n<\/div>\n\n\n\n<div class=\"cppCompiler\">\n<div class=\"cppPoweredBy\">\nPowered By <a target=\"_blank\" href=\"https:\/\/coliru.stacked-crooked.com\/\">Coliru Online Compiler<\/a> and <a \ntarget=\"_blank\" href=\"https:\/\/ace.c9.io\/\">Ace editor<\/a>\n<\/div>\n<div class=\"cppEditorParent\">\n<div class=\"cppEditor\" id=\"editor0\" style=\"width: 500px\">#include &lt;iostream&gt;\n#include &lt;thread&gt;\nusing namespace std;\nvoid foo() {\n     for(int i = 0;i&lt;5;i++) {\n         cout&lt;&lt; &quot;counter value:&quot; &lt;&lt;i&lt;&lt;endl;\n     }\n}\nint main() {\n     thread thr(foo);\n     thr.join();\n     return 0;\n}\n<\/div>\n<\/code>\n<\/div>\n<pre class=\"EditorResult\" id=\"editor0Result\">\n\n<\/pre>\n<\/div>\n\n\n\n<p class=\"has-text-color has-headings-color\">Znajduj\u0105cy si\u0119 powy\u017cej kod ilustruje najprostszy mo\u017cliwy scenariusz. Sp\u00f3jrzmy najpierw na funkcj\u0119 <strong>main.<\/strong> Co w niej si\u0119 znajduje? W linijce 10 tworzymy obiekt klasy <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/thread\/thread\">thread<\/a>. W konstruktorze przekazujemy mu foo. Jej definicja zaczyna si\u0119 w linijce 4. Co robi funkcja foo? Nic niezwyk\u0142ego. Ten niezbyt skomplikowany tw\u00f3r po prostu wypisuje liczby od 0 do 5 w ramach p\u0119tli for. Na bardziej skomplikowane zadania przyjdzie jeszcze czas \ud83d\ude42 <\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Zastanawia ci\u0119 z pewno\u015bci\u0105 linijka 11. Co tam si\u0119 dzieje?. Ot\u00f3\u017c, od momentu utworzenia obiektu w\u0105tku w linijce 10, utworzony w\u0105tek zaczyna wykonywa\u0107 si\u0119 r\u00f3wnolegle wraz z g\u0142\u00f3wnym. Istnieje pewna szansa na to, \u017ce w\u0105tek g\u0142\u00f3wny wykona si\u0119&nbsp;szybciej ni\u017c potomny. Nie powiniene\u015b do tego dopu\u015bci\u0107. Wszelkie w\u0105tki potomne utworzone przez tw\u00f3j program powinny si\u0119 ko\u0144czy\u0107 zawsze przed zako\u0144czeniem dzia\u0142ania programu. Do tego s\u0142u\u017cy metoda join. Dzi\u0119ki niej w\u0105tek g\u0142\u00f3wny mo\u017ce zaczeka\u0107, a\u017c swoj\u0105 prac\u0119 wykona w\u0105tek potomny.<\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">I tu pojawia si\u0119 kolejne pytanie. Czy wstrzymuj\u0105c w\u0105tek g\u0142\u00f3wny, nie rezygnujemy de facto z wszystkich zalet oferowanych przez prac\u0119 wielow\u0105tkow\u0105? Znajdziesz odpowied\u017a na to pytanie czytaj\u0105c dalsz\u0105 cz\u0119\u015b\u0107 artyku\u0142u. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Uruchamiamy kilka w\u0105tk\u00f3w potomnych na raz &#8211; pierwszy praktyczny program<\/h2>\n\n\n\n<div class=\"cppCompiler\">\n<div class=\"cppPoweredBy\">\nPowered By <a target=\"_blank\" href=\"https:\/\/coliru.stacked-crooked.com\/\">Coliru Online Compiler<\/a> and <a target=\"_blank\" href=\"https:\/\/ace.c9.io\/\">Ace editor<\/a>\n<\/div>\n<div class=\"cppEditorParent\">\n<div class=\"cppEditor\" id=\"editor1\" style=\"width: 500px\">#include &lt;iostream&gt;\n#include &lt;thread&gt;\n#include &lt;ctime&gt;\nconst int NUMSIZE = 10;\nusing namespace std;\nint evenSum = 0;\nint oddSum = 0;\nvoid calculateEvenSum(int numbers[]) {\n  for (int i = 0; i &lt; NUMSIZE; i++) {\n    if (!(numbers[i] &amp; 1)) {\n      evenSum += numbers[i];\n    }\n  }\n}\nvoid calculateOddSum(int numbers[]) {\n  for (int i = 0; i &lt; NUMSIZE; i++) {\n    if (numbers[i] &amp; 1) {\n      oddSum += numbers[i];\n    }\n  }\n}\nvoid generateNumbers(int numbers[]) {\n  srand(time(NULL));\n  for (int i = 0; i &lt; NUMSIZE; i++) {\n    numbers[i] = rand() % 100 + 1;\n  }\n}\nvoid printNumberArray(int numbers[]) {\n  for (int i = 0; i &lt; NUMSIZE; i++) {\n    cout&lt;&lt;numbers[i]&lt;&lt;&quot;,&quot;;\n  }\n  cout &lt;&lt;endl;\n}\nint main() {\n  int numbers[NUMSIZE];\n  generateNumbers(numbers);\n  cout &lt;&lt;&quot;Wylosowano liczby : &quot;;\n  printNumberArray(numbers);\n  thread thr1(calculateEvenSum, numbers);\n  thread thr2(calculateOddSum, numbers);\n  thr1.join();\n  thr2.join();\n  cout &lt;&lt;&quot;Suma liczb parzystych to : &quot;&lt;&lt;evenSum &lt;&lt;endl;\n  cout &lt;&lt;&quot;Suma liczb nieparzystych to : &quot;&lt;&lt;oddSum &lt;&lt;endl;\n  return 0;\n}\n<\/div>\n\n<\/div>\n<pre class=\"EditorResult\" id=\"editor1Result\"><\/pre>\n<\/div>\n\n\n\n<p class=\"has-text-color has-headings-color\">Za\u0142\u00f3\u017cmy, \u017ce masz jak\u0105\u015b ogromn\u0105 tablic\u0119 r\u00f3\u017cnych liczb. Twoim zadaniem jest policzenie sumy wszystkich liczb parzystych znajduj\u0105cych si\u0119 w tablicy oraz sum\u0119 wszystkich liczb nieparzystych. Oczywi\u015bcie, mo\u017cna wykona\u0107 to zadanie bez pomocy w\u0105tk\u00f3w. Lecz je\u015bli liczb jest ogrom, o wiele szybciej uzyskamy wynik stosuj\u0105c wiele w\u0105tk\u00f3w. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Funkcje calculateEvenSum i calculateOddSum<\/h3>\n\n\n\n<p class=\"has-text-color has-headings-color\">Powy\u017cszy przyk\u0142ad ilustruje jak prosto mo\u017cna zach\u0119ci\u0107 w\u0105tki do wsp\u00f3\u0142pracy ze sob\u0105. Wynik swojej pracy w\u0105tki zapisuj\u0105 w zmiennych globalnych evenSum i oddSum, kt\u00f3re zdefiniowane s\u0105 w linijkach 6 i 7. Mo\u017cesz zada\u0107 pytanie, dlaczego po prostu funkcja <em>calculateEvenSum<\/em> albo <em>calculateOddSum<\/em> nie zwraca typu int? Poniewa\u017c std::thread nie udost\u0119pnia takiej mo\u017cliwo\u015bci. W takim celu nale\u017cy u\u017cy\u0107 innych typ\u00f3w zdefiniowanych bibliotece standardowej. Zajmiemy si\u0119 nimi w przysz\u0142o\u015bci. <\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Funkcje <em>calculateEvenSum<\/em> i <em>calculateOddSum<\/em> wygl\u0105daj\u0105 dok\u0142adnie tak samo, jakby\u015bmy u\u017cywali ich w zwyk\u0142ym programie jednow\u0105tkowym. Mog\u0105 przyjmowa\u0107 dowolne argumenty. Warto aby\u015b spojrza\u0142 jak zosta\u0142 rozwi\u0105zany spos\u00f3b rozr\u00f3\u017cnienia liczb &#8211; parzysta\/nieparzysta. Najpopularniejszym rozwi\u0105zaniem, kt\u00f3re z pewno\u015bci\u0105 niejednokrotnie widzia\u0142e\u015b jest u\u017cycie operatora modulo. Jest to najprostszy, ale nie najlepszy spos\u00f3b. Dlaczego? Poniewa\u017c modulo jest nieco wolniejsze od sposobu zastosowanego w tym listingu. A na czym \u00f3w trik si\u0119 opiera? Na operacjach bitowych. Zauwa\u017c, \u017ce w zapisie bitowym ka\u017cdej liczby parzystej na pozycji najm\u0142odszego bita znajduje si\u0119 0. Natomiast, je\u015bli rozwa\u017camy liczb\u0119 nieparzyst\u0105, znajdowa\u0107 si\u0119 tam b\u0119dzie jedynka. Sp\u00f3jrz na linijk\u0119 17. U\u017cywamy operatora AND do tego, aby wykona\u0107&nbsp;opisany wcze\u015bniej algorytm. Wi\u0119cej o operatorach bitowych napisz\u0119 w przysz\u0142o\u015bci. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Funkcja main<\/h3>\n\n\n\n<p class=\"has-text-color has-headings-color\">Podobnie jak poprzednio, najwi\u0119cej dzieje si\u0119 w funkcji main. Jej zawarto\u015b\u0107 jest nieco analogiczna w stosunku do wcze\u015bniejszego przyk\u0142adu. Najpierw generujemy liczby. Po ich wygenerowaniu i wypisaniu w\u0105tek g\u0142\u00f3wny praktycznie wykona\u0142 swoje zadanie. Jeszcze tylko uruchamiamy dwa w\u0105tki potomne, kt\u00f3rych zadaniem jest obliczenie sumy liczb parzystych i nieparzystych. (linijka 39 i 40). Nast\u0119pnie, u\u017cywaj\u0105c metody join, w\u0105tek g\u0142\u00f3wny czeka na zako\u0144czenie swoich dw\u00f3ch potomk\u00f3w. Zauwa\u017c, \u017ce obydwie funkcje liczenia sumy liczb wykonuj\u0105 si\u0119 <strong>r\u00f3wnolegle.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Synchronizacja w\u0105tk\u00f3w &#8211; po co i dlaczego?<\/h2>\n\n\n\n<p class=\"has-text-color has-headings-color\">W powy\u017cszych przyk\u0142adach by\u0142a tylko jedna zmienna, kt\u00f3r\u0105 wsp\u00f3\u0142dzieli\u0142y wszystkie w\u0105tki. By\u0142a to tablica numbers[] przechowuj\u0105ca liczby, kt\u00f3rych suma by\u0142a liczona. W\u0105tki potomne tylko odczytywa\u0142y t\u0119 tablic\u0119. Zmienne <em>evenSum&nbsp;<\/em>i <em>oddSum<\/em> by\u0142y modyfikowane tylko przez jeden w\u0105tek na raz, co wynika z kodu programu. Zastan\u00f3w si\u0119, co si\u0119 stanie, je\u015bli dwa w\u0105tki spr\u00f3buj\u0105 w tym samym momencie zapisa\u0107 co\u015b do tej samej zmiennej? Co si\u0119 stanie, je\u015bli w tym samym momencie jeden w\u0105tek b\u0119dzie pr\u00f3bowa\u0142 zapisa\u0107 co\u015b&nbsp;do zmiennej, a inny b\u0119dzie odczytywa\u0142 z tej samej zmiennej? S\u0105 to tzw. <strong>sytuacje&nbsp;hazardowe<\/strong>, kt\u00f3rych powinni\u015bmy unika\u0107 za wszelk\u0105 cen\u0119. S\u0142u\u017c\u0105 do tego tzw. <strong>blokady.<\/strong> Istnieje co najmniej kilka typ\u00f3w blokad. Dzisiaj nauczymy si\u0119 korzysta\u0107 z najprostszej: <strong>muteksa.<\/strong> <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Synchronizacja w\u0105tk\u00f3w &#8211; mutex &#8211; co to takiego?<\/h3>\n\n\n\n<p class=\"has-text-color has-headings-color\">Nie b\u0119dziemy wchodzili w zawi\u0142o\u015bci budowy systemu operacyjnego i w to, jak muteksy realizowane s\u0105 po jego stronie. Og\u00f3lnie mo\u017cemy powiedzie\u0107 \u017ce muteks jest pewnego rodzaju obiektem. Muteks mo\u017ce by\u0107 zablokowany lub nie. To, co znajduje si\u0119&nbsp;mi\u0119dzy wywo\u0142aniem metody <em>lock&nbsp;<\/em>i <em>unlock<\/em> b\u0119dziemy nazywali <strong>sekcj\u0105&nbsp;krytyczn\u0105.<\/strong> W danej chwili tylko jeden w\u0105tek mo\u017ce otrzyma\u0107 dost\u0119p do sekcji krytycznej. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Synchronizacja w\u0105tk\u00f3w &#8211; przyk\u0142ad z \u017cycia<\/h4>\n\n\n\n<p class=\"has-text-color has-headings-color\">Prze\u0142\u00f3\u017cmy sobie to na jak\u0105\u015b sytuacj\u0119 z \u017cycia. Wyobra\u017amy sobie, \u017ce mamy tylko jeden telefon, z kt\u00f3rego chce w jednym momencie skorzysta\u0107 10 os\u00f3b. Telefon jest nasz\u0105 sekcj\u0105 krytyczn\u0105 (mo\u017ce by\u0107 u\u017cywany tylko przez jedn\u0105 osob\u0119 na raz). Natomiast poszczeg\u00f3lne osoby to uruchomione w SO w\u0105tki. Gdy nie zastosujemy synchronizacji, wszyscy rzuc\u0105 si\u0119&nbsp;na raz do tego biednego telefonu i \u017cadna osoba tak naprawd\u0119 nie b\u0119dzie mog\u0142a z niego skorzysta\u0107. Chyba \u017ce si\u0119 pobij\u0105 i wygra najsilniejszy \ud83d\ude09 <\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Za\u0142\u00f3\u017cmy, \u017ce naszym muteksem jest d\u0142o\u0144. Je\u015bli ktokolwiek dotyka telefonu, nikt inny nie mo\u017ce si\u0119 do niego zbli\u017cy\u0107. Wtedy sytuacja staje si\u0119 klarowna i nikt nie bije si\u0119 o dost\u0119p do telefonu. Kiedy pierwsza osoba chce zacz\u0105\u0107 korzysta\u0107 z telefonu, dotyka go (blokada jest zak\u0142adana). Nikt inny nie mo\u017ce w tym momencie korzysta\u0107 z urz\u0105dzenia. Gdy ta osoba sko\u0144czy korzystanie z telefonu, odk\u0142ada go (blokada jest zdejmowana). W tym momencie z urz\u0105dzenia mo\u017ce skorzysta\u0107 inny cz\u0142owiek.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Synchronizacja w\u0105tk\u00f3w &#8211; zachowanie systemu operacyjnego<\/h4>\n\n\n\n<p class=\"has-text-color has-headings-color\">Gdy jaki\u015b w\u0105tek dotrze do wywo\u0142ania metody <em>lock&nbsp;<\/em>muteksa, system operacyjny m\u00f3wi sobie: &#8222;Taki i taki w\u0105tek chce uzyska\u0107 dost\u0119p do sekcji krytycznej. Czy powinienem mu na to pozwoli\u0107?&#8221; Nast\u0119pnie system operacyjny sprawdza, w jakim stanie jest muteks. Je\u015bli jest zablokowany, wtedy SO m\u00f3wi &#8222;nie dostaniesz pozwolenia. Musisz zaczeka\u0107&#8221;. W przeciwnym wypadku: &#8222;wchod\u017a prosz\u0119 i wykonuj swoj\u0105 prac\u0119, a ja oznajmi\u0119 innym w\u0105tkom, \u017ce nie mog\u0105 si\u0119 tu dosta\u0107 dop\u00f3ki ty nie sko\u0144czysz&#8221;. W tym momencie sekcja krytyczna jest blokowana i nikt inny opr\u00f3cz w\u0105tku kt\u00f3ry w\u0142a\u015bnie do niej wszed\u0142, nie ma do niej dost\u0119pu. Kiedy w\u0105tek zako\u0144czy swoj\u0105&nbsp;sekcj\u0119&nbsp;krytyczn\u0105 i dotrze do wywo\u0142ania metody <em>unlock&nbsp;<\/em>muteksa, system operacyjny oznacza muteks, a zarazem sekcj\u0119 krytyczn\u0105 jako dost\u0119pn\u0105 dla innych w\u0105tk\u00f3w.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Gdy brakuje synchronizacji &#8230; <\/h3>\n\n\n\n<div class=\"cppCompiler\">\n<div class=\"cppPoweredBy\">\nPowered By <a target=\"_blank\" href=\"https:\/\/coliru.stacked-crooked.com\/\">Coliru Online Compiler<\/a> and <a target=\"_blank\" href=\"https:\/\/ace.c9.io\/\">Ace editor<\/a>\n<\/div>\n<div class=\"cppEditorParent\">\n<div class=\"cppEditor\" id=\"editor2\" style=\"width: 500px\">#include &lt;iostream&gt;\n#include &lt;thread&gt;\n#include &lt;chrono&gt;\nusing namespace std;\nint counter = 0;\nvoid manageCounter(int id, int wart, bool increment) {\n  for (int i = 0; i &lt; wart; i++) {\n    int localcounter = counter;\n    if (increment == true) {\n      localcounter++;\n      this_thread::sleep_for(chrono::microseconds(50));\n    } else {\n      localcounter=localcounter-1;\n    }\n    counter = localcounter;\n  }\n}\nint main() {\n  thread thr1(manageCounter, 0, 100, true);\n  thread thr2(manageCounter, 1, 100, false);\n  thread thr3(manageCounter, 2, 100, true);\n  thread thr4(manageCounter, 3, 100, false);\n  thread thr5(manageCounter, 4, 100, true);\n  thread thr6(manageCounter, 5, 100, false);\n  thr1.join();\n  thr2.join();\n  thr3.join();\n  thr4.join();\n  thr5.join();\n  thr6.join();\n  cout &lt;&lt;&quot;Ostateczna wart. licznika:&quot;&lt;&lt;counter &lt;&lt;endl;\n  return 0;\n}\n<\/div>\n\n<\/div>\n<pre class=\"EditorResult\" id=\"editor2Result\"><\/pre>\n<\/div>\n\n\n\n<p class=\"has-text-color has-headings-color\">W powy\u017cszym programie pope\u0142nione zosta\u0142o kilka ewidentnych b\u0142\u0119d\u00f3w, kt\u00f3re maj\u0105 unaoczni\u0107 ci, co si\u0119 stanie je\u015bli zapomnisz o synchronizacji wielu w\u0105tk\u00f3w podczas dost\u0119pu do wsp\u00f3\u0142dzielonych zmiennych.<\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Co robi funkcja <em>manageCounter?&nbsp;<\/em>Jak sama nazwa wskazuje, zarz\u0105dza licznikiem. Warto\u015b\u0107 licznika najpierw kopiowana jest do lokalnej zmiennej. Nast\u0119pnie, w zale\u017cno\u015bci od argumentu, jest on zwi\u0119kszany albo zmniejszany okre\u015blon\u0105 liczb\u0119 razy. W linijce 11 zauwa\u017cy\u0142e\u015b pewnie wywo\u0142anie funkcji <em>sleep_for.<\/em> Usypia ona wywo\u0142ywanie w\u0105tku na okre\u015blony czas. U\u017cyli\u015bmy tej funkcji, aby &#8222;symulowa\u0107&#8221;, \u017ce zwi\u0119kszanie warto\u015bci licznika zajmuje nieco wi\u0119cej czasu ni\u017c odejmowanie.<\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Przeanalizujmy dzia\u0142anie funkcji <em>main.<\/em> Uruchamiamy 6 w\u0105tk\u00f3w. Trzy z nich zwi\u0119kszaj\u0105 warto\u015b\u0107 licznika. Trzy z nich j\u0105 obni\u017caj\u0105. Logika podpowiada, \u017ce na samym ko\u0144cu warto\u015b\u0107 licznika powinna wynosi\u0107 0. W ko\u0144cu niezale\u017cnie od tego, w jakiej kolejno\u015bci w\u0105tki b\u0119d\u0105 wykonywa\u0142y swoj\u0105 prac\u0119, to sumuj\u0105c wszystkie wykonywane przez nie obliczenia zawsze powinna wyj\u015b\u0107&nbsp;taka sama warto\u015b\u0107 &#8211; 0. Czy tak rzeczywi\u015bcie jest? Ot\u00f3\u017c, nie do ko\u0144ca. Uruchom program zaprezentowany powy\u017cej i sam si\u0119 przekonaj.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Dlaczego powy\u017cszy program nie dzia\u0142a? <\/h4>\n\n\n\n<p class=\"has-text-color has-headings-color\">Rozpiszmy sobie, jak powy\u017cszy program mo\u017ce dzia\u0142a\u0107. Pami\u0119tasz jak m\u00f3wili\u015bmy na samym pocz\u0105tku, \u017ce ka\u017cdy w\u0105tek otrzymuje co jaki\u015b czas dost\u0119p do procesora? Gdy ten czas up\u0142ynie, dost\u0119p do CPU odbierany jest aktualnemu w\u0105tkowi i przekazywany kolejnemu. Zobaczmy, jakie s\u0105 mo\u017cliwe scenariusze wykonania powy\u017cszego programu <strong>gdy&nbsp;nie&nbsp;zadbamy&nbsp;o&nbsp;synchronizacj\u0119.<\/strong><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Przypadek I<\/h4>\n\n\n\n<table class=\"wp-block-table has-fixed-layout is-style-regular\"><tbody><tr><td>W\u0105tek 1<\/td><td>W\u0105tek 2<\/td><td>Warto\u015b\u0107 zmiennej globalnej counter<\/td><\/tr><tr><td>int localcounter = counter; <\/td><td>&#8212;&#8212;-<\/td><td>0<\/td><\/tr><tr><td>localcounter++;<\/td><td>&#8212;&#8212;-<\/td><td>0<\/td><\/tr><tr><td>&#8212;&#8212;-<\/td><td>int localcounter = counter;<\/td><td>0<\/td><\/tr><tr><td>&#8212;&#8212;-<\/td><td>localcounter=localcounter-1;<\/td><td>0<\/td><\/tr><tr><td>&#8212;&#8212;-<\/td><td>counter=localcounter;<\/td><td>-1<\/td><\/tr><tr><td>counter=localcounter;<\/td><td>&#8212;&#8212;-<\/td><td>1<\/td><\/tr><\/tbody><\/table>\n\n\n\n<h4 class=\"wp-block-heading\">Przypadek II <\/h4>\n\n\n\n<table class=\"wp-block-table has-fixed-layout\"><tbody><tr><td>W\u0105tek 1<\/td><td>W\u0105tek 2<\/td><td>Warto\u015b\u0107 zmiennej globalnej counter<\/td><\/tr><tr><td>int localcounter = counter;<\/td><td>&#8212;&#8212;<\/td><td>0<\/td><\/tr><tr><td>localcounter++;<\/td><td>&#8212;&#8212;<\/td><td>0<\/td><\/tr><tr><td>&#8212;&#8212;<\/td><td>int localcounter = counter;<\/td><td>0<\/td><\/tr><tr><td>&#8212;&#8212;<\/td><td>localcounter=localcounter-1;<\/td><td>0<\/td><\/tr><tr><td>counter=localcounter;<\/td><td>&#8212;&#8212;<\/td><td>1<\/td><\/tr><tr><td>&#8212;&#8212;<\/td><td>counter=localcounter;<\/td><td>-1<\/td><\/tr><\/tbody><\/table>\n\n\n\n<h4 class=\"wp-block-heading\">Przypadek III <\/h4>\n\n\n\n<table class=\"wp-block-table has-fixed-layout\"><tbody><tr><td>W\u0105tek 1<\/td><td>W\u0105tek 2<\/td><td>Warto\u015b\u0107 zmiennej globalnej counter<\/td><\/tr><tr><td>int localcounter = counter;<\/td><td>&#8212;&#8212;<\/td><td>0<\/td><\/tr><tr><td>localcounter++;<\/td><td>&#8212;&#8212;<\/td><td>0<\/td><\/tr><tr><td>counter=localcounter;<\/td><td>&#8212;&#8212;<\/td><td>1<\/td><\/tr><tr><td>&#8212;&#8212;<\/td><td>int localcounter = counter;<\/td><td>1<\/td><\/tr><tr><td>&#8212;&#8212;<\/td><td>localcounter = localcounter-1;<\/td><td>1<\/td><\/tr><tr><td>&#8212;&#8212;<\/td><td>counter=localcounter;<\/td><td>0<\/td><\/tr><\/tbody><\/table>\n\n\n\n<h3 class=\"wp-block-heading\">Co tu si\u0119 wydarzy\u0142o? <\/h3>\n\n\n\n<p class=\"has-text-color has-headings-color\">Jak zauwa\u017cy\u0142e\u015b, ten prosty przyk\u0142ad kodu bez zastosowania synchronizacji mo\u017ce da\u0107 za ka\u017cdym uruchomieniem ca\u0142kowicie inne wyniki. W zale\u017cno\u015bci od tego, kiedy w\u0105tek zostanie <strong>wyw\u0142aszczony&nbsp;<\/strong>(czyli kiedy system operacyjny zdecyduje si\u0119 przekaza\u0107 CPU innemu zadaniu), ostateczny wynik dzia\u0142ania programu mo\u017ce by\u0107 ca\u0142kowicie r\u00f3\u017cny. Zjawisko to przedstawiaj\u0105 tabelki znajduj\u0105ce si\u0119 nieco wy\u017cej. Na trzy rozwa\u017cone przypadki, jedynie w przypadku III w\u0105tki by\u0142y wyw\u0142aszczane w takiej kolejno\u015bci kt\u00f3ra zapewnia\u0142a \u017ce wynik dzia\u0142ania programu by\u0142 prawid\u0142owy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Zastosujmy blokady<\/h3>\n\n\n\n<p class=\"has-text-color has-headings-color\">Dowiedzia\u0142e\u015b si\u0119 wcze\u015bniej wcze\u015bniej, jak dzia\u0142a muteks. Zastosujmy go w praktyce. Zastan\u00f3wmy si\u0119: kt\u00f3ry fragment kodu powinien by\u0107 wykonywany i ko\u0144czony tylko przez jeden w\u0105tek na raz? Desynchronizacja mo\u017ce zacz\u0105\u0107 si\u0119 ju\u017c w linijce 7, w momencie, kiedy warto\u015b\u0107 globalnej zmiennej <em>counter<\/em> przypisujemy do lokalnej <em>localcounter.<\/em> Wynika to tak\u017ce z analizy powy\u017cszych tabelek. Niebezpieczny fragment kodu ko\u0144czy si\u0119 w linijce 15, kiedy do zmiennej globalnej <em>counter&nbsp;<\/em>przypisujemy now\u0105 warto\u015b\u0107 licznika localcounter. Naprawmy ten b\u0142\u0105d i zastosujmy muteksy. <\/p>\n\n\n\n<div class=\"cppCompiler\">\n<div class=\"cppPoweredBy\">\nPowered By <a target=\"_blank\" href=\"https:\/\/coliru.stacked-crooked.com\/\">Coliru Online Compiler<\/a> and <a target=\"_blank\" href=\"https:\/\/ace.c9.io\/\">Ace editor<\/a>\n<\/div>\n<div class=\"cppEditorParent\">\n<div class=\"cppEditor\" id=\"editor3\" style=\"width: 500px\">#include &lt;iostream&gt;\n#include &lt;thread&gt;\n#include &lt;chrono&gt;\n#include &lt;mutex&gt;\nusing namespace std;\nint counter = 0;\nmutex mut;\nvoid manageCounter(int id, int wart, bool increment) {\n  for (int i = 0; i &lt; wart; i++) {\n    mut.lock();\n    int localcounter = counter;\n    if (increment == true) {\n      localcounter++;\n      this_thread::sleep_for(chrono::microseconds(50));\n    } else {\n      localcounter=localcounter-1;\n    }\n    counter = localcounter;\n    mut.unlock();\n  }\n}\nint main() {\n  thread thr1(manageCounter, 0, 100, true);\n  thread thr2(manageCounter, 1, 100, false);\n  thread thr3(manageCounter, 2, 100, true);\n  thread thr4(manageCounter, 3, 100, false);\n  thread thr5(manageCounter, 4, 100, true);\n  thread thr6(manageCounter, 5, 100, false);\n  thr1.join();\n  thr2.join();\n  thr3.join();\n  thr4.join();\n  thr5.join();\n  thr6.join();\n  cout &lt;&lt;&quot;Ostateczna wart. licznika:&quot;&lt;&lt;counter &lt;&lt;endl;\n  return 0;\n}\n<\/div>\n\n<\/div>\n<pre class=\"EditorResult\" id=\"editor3Result\"><\/pre>\n<\/div>\n\n\n\n<p class=\"has-text-color has-headings-color\">Skompiluj i uruchom powy\u017cszy program. Widzisz, \u017ce teraz zawsze zwraca on warto\u015b\u0107 0? Jest to oczekiwany przez nas wynik. Przeanalizujmy, jak muteks pozwoli\u0142 nam upora\u0107 si\u0119 z problemem braku synchronizacji. <\/p>\n\n\n\n<p class=\"has-text-color has-headings-color\">Obiekt muteksu zadeklarowali\u015bmy globalnie. Dlaczego? Poniewa\u017c ka\u017cdy w\u0105tek musi mie\u0107 dost\u0119p do <strong>tego&nbsp;samego<\/strong> muteksu. System operacyjny musi sobie zapisa\u0107, \u017ce ten i ten muteks jest zablokowany przez dany w\u0105tek. Je\u015bli inny w\u0105tek pr\u00f3buje zablokowa\u0107 ten sam muteks, system operacyjny nie mo\u017ce mu na to pozwoli\u0107. Gdyby\u015bmy obiekt muteksa  utworzyli wewn\u0105trz funkcji <em>manageCounter<\/em> ka\u017cdy w\u0105tek utworzy\u0142by swojego w\u0142asnego muteksa. Wtedy de facto nie dzia\u0142a\u0142yby one poprawnie, gdy\u017c stan obiektu muteksa nie by\u0142by wsp\u00f3\u0142dzielony mi\u0119dzy w\u0105tkami. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Synchronizacja w\u0105tk\u00f3w &#8211; proste zadanie<\/h2>\n\n\n\n<p class=\"has-text-color has-headings-color\">Przypomnij sobie przyk\u0142ad z lud\u017ami, kt\u00f3rzy chcieli skorzysta\u0107 z jednego telefonu. Twoim zadaniem b\u0119dzie rozwi\u0105zanie postawionego w tamtym przyk\u0142adzie problemu. Sp\u00f3jrz na poni\u017cszy kod.<\/p>\n\n\n\n<div class=\"cppCompiler\">\n<div class=\"cppPoweredBy\">\nPowered By <a target=\"_blank\" href=\"https:\/\/coliru.stacked-crooked.com\/\">Coliru Online Compiler<\/a> and <a target=\"_blank\" href=\"https:\/\/ace.c9.io\/\">Ace editor<\/a>\n<\/div>\n<div class=\"cppEditorParent\">\n<div class=\"cppEditor\" id=\"editor4\" style=\"width: 500px\">#include &lt;iostream&gt;\n#include &lt;thread&gt;\n#include &lt;mutex&gt;\nconst int SIZE=10;\nusing namespace std;\n\nint counter = 0;\nvoid call(int personID) {\n    cout&lt;&lt;&quot;Osoba nr :&quot;&lt;&lt;personID&lt;&lt;&quot; dzwoni&quot;&lt;&lt;endl;\n}\nvoid fight(int personID) {\n    cout&lt;&lt;&quot;Osoba nr :&quot;&lt;&lt;personID&lt;&lt;&quot;walczy o dost\u0119p do telefonu&quot;&lt;&lt;endl;\n}\nvoid useThePhone(int personID) {\n    while(counter&gt;0) fight(personID);\n    counter++;\n    call(personID);\n    counter= counter-1;\n}\n\nint main()\n{\n    thread thr1(useThePhone,0);\n    thread thr2(useThePhone,1);\n    thread thr3(useThePhone,2);\n    thread thr4(useThePhone,3);\n    thr1.join();\n    thr2.join();\n    thr3.join();\n    thr4.join();\n}\n<\/div>\n\n<\/div>\n<pre class=\"EditorResult\" id=\"editor4Result\"><\/pre>\n<\/div>\n\n\n\n<p class=\"has-text-color has-headings-color\">Funkcja fight nie powinna by\u0107 uruchomiona ani raz. Wszyscy powinni grzecznie ustawi\u0107 si\u0119 w kolejk\u0119 i skorzysta\u0107 z telefonu.<strong> Zabezpiecz powy\u017cszy program za pomoc\u0105 muteks\u00f3w. <\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">W\u0105tki &#8211; co dalej?<\/h2>\n\n\n\n<p class=\"has-text-color has-headings-color\">Ten wpis na blogu zawiera jedynie same podstawy korzystania z w\u0105tk\u00f3w. Istnieje wiele wi\u0119cej problem\u00f3w synchronizacji ni\u017c te kt\u00f3re pozna\u0142e\u015b w tym artykule. Biblioteka standardowa udost\u0119pnia tak\u017ce kilka przydatnych w pracy wielow\u0105tkowej klas, kt\u00f3rych nie poznali\u015bmy do tej pory. Niemniej, podstawy te pozwoli\u0142y ci z pewno\u015bci\u0105 zrozumie\u0107 czym jest wielow\u0105tkowo\u015b\u0107, jak j\u0105 zastosowa\u0107 w j\u0119zyku C++. Zrozumia\u0142e\u015b tak\u017ce (je\u015bli wykona\u0142e\u015b zadanie domowe :)) jak dzia\u0142a synchronizacja w\u0105tk\u00f3w za pomoc\u0105 muteksa. <\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">9<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span> Czy pisa\u0142e\u015b kiedy\u015b program, kt\u00f3ry potrzebowa\u0142 du\u017co mocy CPU? Zastanawia\u0142e\u015b si\u0119 dlaczego twoja aplikacja u\u017cywa maksymalnie jednego rdzenia, nawet je\u015bli masz ich kilka\/kilkana\u015bcie? Czy tworzy\u0142e\u015b kiedy\u015b program, kt\u00f3ra odczytywa\u0142 z &#8230;<\/p>\n","protected":false},"author":1,"featured_media":675,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31],"tags":[],"_links":{"self":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/543"}],"collection":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/comments?post=543"}],"version-history":[{"count":130,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/543\/revisions"}],"predecessor-version":[{"id":694,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/543\/revisions\/694"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media\/675"}],"wp:attachment":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media?parent=543"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/categories?post=543"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/tags?post=543"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}