===== [ekstra] Wątki w C++ ===== Język C+''''+ (od wersji C+''''+11) ma w bibliotece standardowej obsługę wątków. \\ API do obsługi wątków w C+''''+ zostało przeniesione z ''boost::thread'', z wyjątkiem obsługi przerywania wątków (''thread::interrupt()'')((W C+''''+20 pojawiła się klasa ''std::jthread'' która pozwala zasygnalizować wątkowi że powinien się przerwać, ale wywołanie ''request_stop'' __nie__ przerywa wywołań systemowych (np. ''read''). )). Przykład prostego programu: #include #include void funkcja(const char * argument){ printf("Hello %s\n", argument); } int main(){ std::thread t(funkcja, "world"); t.join(); return 0; } Podsumowanie tworzenia wątków: std::thread t1(funkcja); // tworzy obiekt 't1', tworzy nowy wątek i uruchamia w nim 'funkcja()'. std::thread t2; // tworzy pusty obiekt 't2'. t2 = std::thread(funkcja); /* tworzy nowy obiekt w miejscu "t2", niszczy poprzedni obiekt, tworzy nowy wątek i uruchamia w nim 'funkcja()' */ // thread t3 = t2; // kod NIEPOPRAWNY – wątków nie można kopiować thread t3 = std::move(t2); // ale wątki można przesuwać std::thread t4(funkcja2, 1, 2, "z"); /* tworzy obiekt 't4', tworzy nowy wątek programu i uruchamia w nim 'funkcja2(1, 2, "z")'*/ Podsumowanie zajmowania się wątkiem: t1.join(); // czeka na zakończenie wątku // thread * w = new thread(h); delete w; // niepoprawne – jeśli zmienna reprezentująca wątek // ginie (''~thread::thread'') przed zakończeniem wątku, // to program jest przerywany // Jeśli główny wątek (main) się zakończy, pozostałe są zabijane (zachowanie inne niż np. w Javie) t2.detach() // rozłącza wątek ze zmienną go reprezentującą. Można zmazać zmienną, wątek przeżyje. std::thread(i).detach(); // tworzy nowy wątek bez deklaracji zmiennej która będzie go reprezentować. W C++ ustandaryzowano też zmienne lokalne dla wątku – w deklaracji zmiennej wystarczy dodać słowo kluczowe ''thread_local'', np: thread_local int tid = i.fetch_add(1); Ponadto, dodano API do zamków, zmiennych warunkowych, zmiennych atomowych i futures * http://en.cppreference.com/w/cpp/atomic * http://en.cppreference.com/w/cpp/thread Przykład synchronizacji między wątkami (producent-konsument): #include #include #include #include #include std::mutex mtx; std::condition_variable cv; std::list slowa; thread_local std::string slowo; void consumer(){ while(true){ { std::unique_lock lock(mtx); cv.wait(lock, []{return slowa.size()!=0;}); slowo = slowa.front(); slowa.pop_front(); } std::cout << slowo << std::endl; } } int main(){ std::thread t(consumer); while(true) { std::cin >> slowo; { std::unique_lock lock(mtx); slowa.push_back(slowo); cv.notify_one(); } } } ===== [ekstra] w C++ ===== Bardzo krótkie streszczenie: #include #include #include using namespace std; using namespace std::placeholders; void b(char c){ cout << c << endl;} class C{ public: void operator()() {cout << 'C' << endl;} void operator()(char c) {cout << c << endl;} } objC; class E{ const char * t_ = "ABCDEFGH"; public: char f(int i){ cout << t_[i] << endl; return t_[i];} void g(){t_="G";} } objE; int main() { thread([]{cout << "A" << endl;}).join(); // lambda – http://en.cppreference.com/w/cpp/language/lambda thread(b, 'B').join(); // "zwykła" funkcja thread(objC).join(); // operator() thread(objC, 'D').join(); // operator() z argumentami thread(bind(&E::f, objE, 4)).join(); // funkcja na rzecz obiektu z ustalonym argumentem (currying) thread(bind(&E::f, objE, _1), 5).join(); // funkcja na rzecz obiektu z nieustalonym argumentem function funR(bind(&E::f, ref(objE), _1)); // funkcja na rzecz obiektu wołanego przez referencję function funC(bind(&E::f, objE, _1)); // funkcja na rzecz obiektu w stanie z chwili tworzenia funcC objE.g(); // modyfikacja obiektu thread(funR, 0).join(); // wywołanie zmodyfikowanego obiektu - funcR zna obiekt przez referencję thread(funC, 7).join(); // wywołanie zmodyfikowanego obiektu - funcC zna obiekt przez wartość return 0; }