Threads teilen Daten

Inhaltsverzeichnis[Anzeigen]

Die große Herausforderung mit Threads beginnt dann, wenn sich diese Daten teilen und diese nicht konstant sind.

Kritischer Wettlauf und kritischer Bereich

Im Zusammenhang mit von Threads gemeinsam verwendeten Daten wird gerne von einem kritischen Wettlauf oder auch kritischem Bereich gesprochen. Doch was ist das?

Kritischer Wettlauf (Race Condition)
    Ein kritischer Wettlauf entsteht genau dann, wenn mindestens zwei Threads gleichzeitig ein Datum verwenden, wobei zumindestens ein Thread versucht, diese zu modifizieren.
Kritischer Bereich (Critial Section)
    Ein kritischer Bereich ist ein zusammenhängender Datenbereich, in dem nur ein Thread Zugriff auf die Daten haben darf.

 

Enthält ein Programm einen kritischen Wettlauf, dann ist das Programmverhalten undefiniert. Anders ausgedrückt, jedes erdenkliche und unerdenkliche Verhalten ist möglich.

Schön lässt sich dies verschränkte Ausführen von Threads visualisieren, wenn mehrere Threads versuchen, gleichzeitig auf std::cout zu schreiben. std::cout ist daher das gemeinsame Datum, dass es vor dem gleichzeitigen modifizierenden Zugriff mehrerer Threads zu schützen gilt.  

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <chrono>
#include <iostream>
#include <thread>

class Worker{
public:
  Worker(std::string n):name(n){};
  
    void operator() (){
      for (int i= 1; i <= 3; ++i){
	// begin work
	std::this_thread::sleep_for(std::chrono::milliseconds(200));
	// end work
	std::cout << name << ": " << "Work " << i << " done !!!" << std::endl;
      }
      
    }
private:
  std::string name;
};


int main(){

  std::cout << std::endl;
  
  std::cout << "Boss: Let's start working.\n\n";
 
  std::thread herb= std::thread(Worker("Herb"));
  std::thread andrei= std::thread(Worker("  Andrei"));
  std::thread scott= std::thread(Worker("    Scott"));
  std::thread bjarne= std::thread(Worker("      Bjarne"));
  std::thread andrew= std::thread(Worker("        Andrew"));
  std::thread david= std::thread(Worker("          David"));
  
  herb.join();
  andrei.join();
  scott.join();
  bjarne.join();
  andrew.join();
  david.join();
  
  std::cout << "\n" << "Boss: Let's go home." << std::endl;
  
  std::cout << std::endl;

}

 

Der Boss gibt seinen sechs Arbeitern (Zeile 29 - 34)  jeweils drei Arbeitspakete in den Zeilen 9 - 15. Hat ein Arbeiter sein Arbeitspaket erledigt, schreit er dies zum Boss (main-Thread) zurück (Zeile 14). Hat der Boss alle Benachrichtigungen von seinen Arbeitern erhalten, schickt er sie in den wohlverdienten Feierabend (Zeile 43). 

 Was für ein Durcheinander!

 bossWorker

Am nächsten Tag wird es auch nicht besser. Die Arbeiter schreien wiederum vollkommen unkoordiniert durcheinander.

bossWorker1

Die naheliegende Möglichkeit, den Zugriff der Threads auf die gemeinsame Variable std::cout zu synchronisieren, ist ein Mutex.

Exkurs: std::cout ist threadsicher

Der C++11 Standard sicher zu, dass die einzelnen Zeichen auf den Ausgabestream std::cout vor gleichzeitiger Modifikation mehrerer Threads nicht geschützt werden müssen. Jedes Zeichen wird atomar ausgegeben. Natürlich können mehrere Ausgabeanweisungen wie in dem Beispiel beliebig vermischt werden. Das ist aber nur ein optisches Problem. Das Programm ist wohldefiniert. Diese Aussage gilt neben den Ausgabestream std::cout für alle weiteren Ein- und Ausgabebstreams in C++.

Mutex

Ein Mutex steht für Mutual Exclusion. Dieser sichert zu, dass der kritische Bereich exklusiv von einem Thread verwendet wird.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>

std::mutex coutMutex;

class Worker{
public:
  Worker(std::string n):name(n){};
 
    void operator() (){
      for (int i= 1; i <= 3; ++i){
	// begin work
	std::this_thread::sleep_for(std::chrono::milliseconds(200));
	// end work
	coutMutex.lock();
	std::cout << name << ": " << "Work " << i << " done !!!" << std::endl;
	coutMutex.unlock();
      }
    }
private:
  std::string name;
};


int main(){

  std::cout << std::endl;
  
  std::cout << "Boss: Let's start working." << "\n\n";
 
  std::thread herb= std::thread(Worker("Herb"));
  std::thread andrei= std::thread(Worker("  Andrei"));
  std::thread scott= std::thread(Worker("    Scott"));
  std::thread bjarne= std::thread(Worker("      Bjarne"));
  std::thread andrew= std::thread(Worker("        Andrew"));
  std::thread david= std::thread(Worker("          David"));
  
  herb.join();
  andrei.join();
  scott.join();
  bjarne.join();
  andrew.join();
  david.join();
  
  std::cout << "\n" << "Boss: Let's go home." << std::endl;
  
  std::cout << std::endl;

}

 

Der entscheidende Unterschied zum ersten nicht synchronisierten Programm sind in diesem Programm die Zeilen 17 und 19. Durch die Methodenaufrufe coutMutex.lock() und coutMutex.unlock() wird der kritische Bereich erklärt, der nur von einem Thread zu einem Zeitpunkt verwendet werden darf. Dadurch ist der Zugriff auf den Ausgabestream std::cout synchronisiert. Nun löst sich das Geschrei der Arbeiter in Wohlgefallen auf.

bossWorkerSynchonized

Mutexe bergen ihre eigenen Gefahren. Dazu aber mehr im nächsten Artikel.

Hintergrundinformationen

C++11 kennt mehrere Variationen von Mutexen. So gibt es Mutexe, die rekursiv aufgerufen oder mit Zeitbedingungen verwendet werden können.

C++14 führt einen weiteren Mutex ein, der von mehreren Threads gleichzeitig verwendet werden kann. Dieser Mutex bildet die Grundlage für Reader-Writer Locks. Die Details zu den Mutexvarianten lassen sich schön auf en.cppreference.com nachlesen.

 

 

 

 

 

 

 

 

title page smalltitle page small Go to Leanpub/cpplibrary "What every professional C++ programmer should know about the C++ standard library".   Hole dir dein E-Book. Unterstütze meinen Blog.

Tags: C++14, Mutexe

Kommentare   

+1 #1 Gast 2016-01-29 09:18
Ich lese hier zum ersten mal. Mir fiel sofort im Vergleich zu anderen C++-Blogs positiv auf, das sich endlich mal jemand etwas um Deutsch bemüht, statt einfach nur wie üblich mit zweifelhaftem Erfolg das Englische zu übernehmen.
Zitieren
+1 #2 Rainer Grimm 2016-01-29 18:52
zitiere Gast:
Ich lese hier zum ersten mal. Mir fiel sofort im Vergleich zu anderen C++-Blogs positiv auf, das sich endlich mal jemand etwas um Deutsch bemüht, statt einfach nur wie üblich mit zweifelhaftem Erfolg das Englische zu übernehmen.

Tatsächlich habe ich länger überlegt, ob ich in Deutsch oder in Englisch schreiben soll. Der Grund für Deutsch war dann relativ naheliegend. Zum einen fühle ich mich in der Deutschen Sprache sicherer, zum andern ist die automatische Übersetzung meines Artikels in die englische Sprache ausreichend gut.
Zitieren
0 #3 Triple Arthrodesis 2016-02-27 16:43
Hi there! This is kind of off topic but I need some guidance from an established blog.
Is it very difficult to set up your own blog? I'm not very techincal but I
can figure things out pretty quick. I'm thinking about making my own but I'm not sure where to begin. Do you
have any ideas or suggestions? With thanks

Feel free to visit my blog ... Triple Arthrodesis: http://wumeixf.com/comment/html/index.php?page=1&id=8529
Zitieren
0 #4 LukeMGahan 2016-07-27 04:14
I've been exploring for a bit for virtually any high quality
articles or weblog posts within this type of house
. Exploring in Yahoo I eventually came across this
website. Studying this information So i'm satisfied to exhibit that I've a tremendously
good uncanny feeling I discovered exactly the things i needed.
I a whole lot definitely will make certain to
will not forget this website and present it a glance regularly.


Here is my blog post LukeMGahan: http://epk-time.kz/?option=com_k2&view=itemlist&task=user&id=246264
Zitieren
0 #5 forex forum 2016-12-15 07:49
I know this web page gives quality depending posts and extra stuff, is there
any other website which offers these kinds of information in quality?
Zitieren
0 #6 forex forum 2016-12-28 10:58
It's really a nice and useful piece of info.
I'm glad that you just shared this useful info with us.

Please stay us up to date like this. Thank you for sharing.
Zitieren
0 #7 world wide invest 2016-12-28 22:51
Great article, just what I needed.
Zitieren

Kommentar schreiben


Abonniere den Newsletter (+ pdf Päckchen)

Beiträge-Archiv

Sourcecode

Neuste Kommentare