Advanced Java Services | std::thread C++ 11 |
Es werden leicht verschiedene Ansätze gezeigt.
Mit der folgenden Klasse gelingt es, Threads später zu starten und auch länger laufen zu lassen als main.
/* Legt ein Threadobject an, ohne einen Thread zu starten, das gelingt mit dem Defaultkonstruktor von std::thread. Der eigentliche Thread wird dann der start-Methode übergeben. Diese bringt diesen Thread mit move oder swap in den privaten Datenteil. Über die start-Methode kann jeder beliebige std::thread übergeben werden. Diese arbeiten mit beliebigen Funktionen. Ein join() im Destruktor sorgt dafür, daß am Ende aufgeräumt wird. Hier kann es passieren, daß der Thread länger lebt als main. */ class Thread1 { private: std::thread th; public: Thread1() {}; virtual ~Thread1() { std::cout << "destruktor-id" << std::this_thread::get_id() << std::endl; this->th.join(); std::cout << "destruktor-end-id" << std::this_thread::get_id() << std::endl; }; // startet einen thread der eine externe funktion vewendet void start(std::thread th) { this->th.swap(th); // geht beides //this->th = std::move(th); }; };
Die folgende Methode soll in einem eigenen Thread laufen
/* wird von test_Thread1 verwendet */ void sayHello(int howOften) { for(int i=0; i<howOften; i++ ) { cout << " hello-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } };
Die folgende Methode legt ein Objekt vom Typ Thread1 an und startet den Thread.
void test_Thread1() { cout << "Thread1 example\n" << endl; // Thread1 thread1; // leerer Thread for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } // anonaymes std::thread Objekt wird übergeben thread1.start( std::thread(sayHello, 7)) ; // muß so verwendet werden for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } cout << "main-end" << endl; }
Zwei Ausgaben
Thread2 hat eine Memberfunction run(), die in einem Thread laufen soll. Mit Hilfe von std::move() gelingt das. Damit der Thread nur einmal gestartet werden kann gibt es eine Abfrage in start().
/* Thread2 hat eine Memberfunction run(), die in einem Thread laufen soll. Mit Hilfe von std::move() gelingt das. Damit der Thread nur einmal gestartet werden kann gibt es eine Abfrage in start(). */ class Thread2 { private: std::thread th; bool running = false; public: Thread2() {}; virtual ~Thread2() { std::cout << "destruktor-id" << std::this_thread::get_id() << std::endl; this->th.join(); std::cout << "destruktor-end-id" << std::this_thread::get_id() << std::endl; }; void start() // darf nur einmal passieren { if (running == false) { this->running = true; this->th = std::move( std::thread(&Thread2::run, this) ); // // swap geht hier nicht } }; void run() { for(int i=0; i<7; i++ ) { std::cout << "run-id" << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } };
Die Testmethode
/* Testet die Klasse Thread2. Die Klasse verwendet eine eigene Memberfunction als Threadmethode */ void test_Thread2() { cout << "Thread2 example\n" << endl; // Thread2 thr; for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } thr.start() ; // for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } cout << "main-end" << endl; }
Zwei Ausgaben
Beispiel 3 ist eine Variation von Beispiel 2 und zeigt, daß die interne Methode run() auch mit Parametern aufgerufen werden kann.
/* Variation von Thread2 Thread3 hat eine Memberfunction run(), mit zwei Parametern. */ class Thread3 { private: std::thread th; bool running = false; public: Thread3() {}; virtual ~Thread3() { std::cout << "destruktor-id" << std::this_thread::get_id() << std::endl; this->th.join(); std::cout << "destruktor-end-id" << std::this_thread::get_id() << std::endl; }; void start(int data, int data2) // darf nur einmal passieren { if (running == false) { this->running = true; this->th = std::move( std::thread(&Thread3::run, this, data, data2) ); // // swap geht hier nicht } }; void run(int data, int data2) { for(int i=0; i<data2; i++ ) { std::cout << "run-id" << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } }; };
Die Testmethode
/* Testet Thread3 */ void test_Thread3() { cout << "Thread3 example\n" << endl; // Thread3 thr; for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } // sayHello sollte zuerst kommen, dann run3 thr.start(17, 7); for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } cout << "main-end" << endl; }
Zwei Ausgaben
Der Thread in der Klasse erhält über start() einen äußeren std::thread, auf den er mit join() wartet
/* Bekommt über die start()-Methode einen std::thread von außen, auf den der interne Thread mit join() wartet */ class Thread4 { private: std::thread th; std::thread other; bool running = false; public: Thread4() {}; virtual ~Thread4() { std::cout << "destruktor-id" << std::this_thread::get_id() << std::endl; this->th.join(); std::cout << "destruktor-end-id" << std::this_thread::get_id() << std::endl; }; void start(std::thread other) // darf nur einmal passieren { this->other = std::move( other ); // if (running == false) { this->running = true; this->th = std::move( std::thread(&Thread4::run, this) ); // // swap geht hier nicht } }; void run() { if( this->other.joinable() ) this->other.join(); for(int i=0; i<3; i++ ) { std::cout << "run-id" << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } }; };
Die Testmethode
/* Erst kommt main, dann wird der dem Threadobjekt über start() ein äußerer Thread übergeben, der sayHello() aufruft, da der innere Thread auf diesen wartet kommen due run-Ausgaben nach den hello-Ausgaben, währen main noch dazwischen Ausgaben macht */ void test_Thread4() { cout << "Thread4 example\n" << endl; // Thread4 thr; for(int i=0; i<3; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } thr.start( std::thread(sayHello, 3) ); // 3 mal hello, 3 mal run for(int i=0; i<4; i++ ) { cout << "main-id" << std::this_thread::get_id() << endl; std::this_thread::sleep_for (std::chrono::seconds(1)); } cout << "main-end" << endl; }
Zwei Ausgaben