Die Boost C++ Bibliotheken

Multithreading

Fast alle Klassen von Boost.Signals2 sind thread-safe. So können Sie zum Beispiel von mehreren Threads aus auf Objekte vom Typ boost::signals2::signal und boost::signals2::connection zugreifen.

Beachten Sie, dass boost::signals2::shared_connection_block nicht thread-safe ist. Das stellt insofern kein Problem dar, als dass Sie mehrere Objekte vom Typ boost::signals2::shared_connection_block in unterschiedlichen Threads erstellen können, die alle mit dem gleichen Verbindungsobjekt initialisiert werden können.

Beispiel 67.17. boost::signals2::signal ist thread-safe
#include <boost/signals2.hpp>
#include <thread>
#include <mutex>
#include <iostream>

boost::signals2::signal<void(int)> s;
std::mutex m;

void loop()
{
  for (int i = 0; i < 100; ++i)
    s(i);
}

int main()
{
  s.connect([](int i){
    std::lock_guard<std::mutex> lock{m};
    std::cout << i << '\n';
  });
  std::thread t1{loop};
  std::thread t2{loop};
  t1.join();
  t2.join();
}

Im Beispiel 67.17 wird die Funktion loop() in zwei Threads gestartet, in denen jeweils hundertmal auf s zugegriffen wird, um die mit diesem Objekt verknüpfte Lambda-Funktion aufzurufen. Dieser gleichzeitige Zugriff auf ein Objekt vom Typ boost::signals2::signal in mehreren Threads wird von Boost.Signals2 explizit unterstützt.

Beispiel 67.17 gibt Zahlen von 0 bis 99 aus. Da die Variable i in zwei Threads inkrementiert und per Lambda-Funktion ausgegeben wird, wird nicht nur jede Zahl zweimal ausgegeben. Es kommt außerdem zu Überschneidungen. Entscheidend ist aber, dass es zu keinem Programmabsturz kommen kann, da mehrere Threads auf boost::signals2::signal zugreifen dürfen.

Beachten Sie, dass im Beispiel 67.17 dennoch eine Synchronisation stattfindet. Da das Programm zwei Threads verwendet, die beide auf s zugreifen, wird auch die mit s verknüpfte Lambda-Funktion in zwei Threads ausgeführt. Damit die Ausgabe innerhalb der Lambda-Funktion jeweils komplett erfolgt und sowohl die Zahl als auch das Zeilenende ausgegeben wird, bevor der andere Thread seine Ausgabe beginnt, wird der Zugriff auf die Standardausgabe mit einem Mutex synchronisiert. So ist garantiert, dass zu jedem beliebigen Zeitpunkt nur ein Thread std::cout verwendet und die Ausgabe vom anderen Thread nicht unterbrochen werden kann.

Boost.Signals2 unterstützt standardmäßig Multithreading. Verwenden Sie in einem Programm nur einen einzigen Thread, können Sie diese Unterstützung deaktivieren.

Beispiel 67.18. boost::signals2::signal ohne Thread-Safety
#include <boost/signals2.hpp>
#include <iostream>

using namespace boost::signals2;

signal<void()> s;

int main()
{
  typedef keywords::mutex_type<dummy_mutex> dummy_mutex;
  signal_type<void(), dummy_mutex>::type s;
  s.connect([]{ std::cout << "Hello, world!\n"; });
  s();
}

boost::signals2::signal unterstützt zahlreiche Template-Parameter. Da es der letzte Template-Parameter ist, der den Mutex-Typ definiert, der von boost::signals2::signal zur Synchronisierung von Threads verwendet wird, bietet Boost.Signals2 eine einfachere Möglichkeit an, als die vollständige Liste aller Template-Parameter an boost::signals2::signal übergeben zu müssen.

Im Namensraum boost::signals2::keywords sind Klassen definiert, mit denen Template-Parameter mit Namen angegeben werden können. So kann auf boost::signals2::keywords::mutex_type zugegriffen werden, um den Mutex-Typ als zweiten Template-Parameter an boost::signals2::signal_type zu übergeben. Beachten Sie, dass in diesem Fall auf boost::signals2::signal_type und nicht auf boost::signals2::signal zugegriffen werden muss. Über boost::signals2::signal_type::type wird der Typ erhalten, der boost::signals2::signal entspricht und notwendig ist, um das Signal s zu definieren.

Boost.Signals2 stellt mit boost::signals2::dummy_mutex eine Mutex-Implementation zur Verfügung, die leer ist und nichts macht. Wird wie im Beispiel 67.18 ein Signal mit dieser Klasse definiert, unterstützt es kein Multithreading.