Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Dieses Dokument enthält eine Übersicht über die Concurrency Runtime. Es beschreibt die Vorteile der Concurrency Runtime, wann sie verwendet wird und wie ihre Komponenten miteinander und mit dem Betriebssystem und den Anwendungen interagieren.
Abschnitte
Dieses Dokument enthält folgende Abschnitte:
Implementierung der Concurrency Runtime Historie
In Visual Studio 2010 bis 2013 war die Concurrency Runtime in msvcr100.dll bis msvcr120.dll integriert. Als das UCRT Refactoring in Visual Studio 2015 stattfand, wurde diese DLL in drei Elemente aufgeteilt:
ucrtbase.dll – C API, die in Windows 10 ausgeliefert und über Windows Update-
vcruntime140.dll – Compiler Support Funktionen und EH Runtime, ausgeliefert über Visual Studio
concrt140.dll – Concurrency Runtime, ausgeliefert über Visual Studio. Erforderlich für parallele Container und Algorithmen wie z. B.
concurrency::parallel_for. Außerdem benötigt die STL diese DLL unter Windows XP, um Synchronisations-Primitive zu betreiben, da Windows XP nicht über Bedingungsvariablen verfügt.
In Visual Studio 2015 und höher ist der Concurrency Runtime-Taskplaner nicht mehr der Planer für die Aufgabenklasse und verwandte Typen in „ppltasks.h“. Diese Typen verwenden jetzt den Windows-Threadpool für eine bessere Leistung und Interoperabilität mit Windows-Synchronisierungsprimitiven.
Warum eine Concurrency Runtime wichtig ist
Eine Laufzeit für die Parallelität bietet die Einheitlichkeit und Vorhersagbarkeit für Anwendungen und Anwendungskomponenten, die gleichzeitig ausgeführt werden. Zwei Beispiele für die Vorteile der Concurrency Runtime sind kooperatives Task Scheduling und kooperative Blockierung.
Die Concurrency Runtime verwendet einen kooperativen Aufgabenplaner, der einen Arbeitsübernahme-Algorithmus implementiert, um die Arbeit effizient auf die Computerressourcen zu verteilen. Betrachten Sie beispielsweise eine Anwendung mit zwei Threads, die beide von der gleichen Laufzeit verwaltet werden. Wenn ein Thread die geplante Aufgabe abgeschlossen hat, kann dieser die Arbeit des anderen Threads auslagern. Dieser Mechanismus gleicht die gesamte Arbeitsauslastung der Anwendung aus.
Die Concurrency Runtime stellt außerdem Synchronisierungsprimitiven zur Verfügung, die die kooperative Blockierung zum Synchronisieren des Zugriffs auf die Ressourcen nutzen. Betrachten Sie z. B. eine Aufgabe, bei der der exklusive Zugriff auf eine freigegebene Ressource gewährleistet sein muss. Durch die kooperative Blockierung kann die Laufzeit das verbleibende Quantum verwenden, um eine andere Aufgabe ausführen, während die erste Aufgabe auf die Ressource wartet. Durch diesen Mechanismus wird die maximale Auslastung der Computerressourcen hochgestuft.
Aufbau
Die Concurrency Runtime ist in vier Komponenten unterteilt: die Parallel Patterns Library (PPL), die Asynchronous Agents Library, der Taskplaner und der Ressourcen-Manager. Diese Komponenten befinden sich zwischen dem Betriebssystem und den Anwendungen. Die folgende Abbildung zeigt, wie die Concurrency Runtime-Komponenten zwischen dem Betriebssystem und den Anwendungen interagieren:
Concurrency Runtime Architektur

Wichtig
Die Komponenten Task Scheduler und Resource Manager sind nicht in einer Universal Windows Platform (UWP)-App verfügbar oder wenn Sie die Task-Klasse oder andere Typen in ppltasks.h verwenden.
Die Concurrency Runtime ist in hohem Maße kombinierbar, d.h. Sie können vorhandene Funktionen kombinieren, um mehr zu tun. Die Concurrency Runtime kombiniert viele Funktionen aus Komponenten auf niedrigerer Ebene, wie z. B. parallele Algorithmen.
Die Concurrency Runtime stellt außerdem Synchronisierungsprimitiven zur Verfügung, die die kooperative Blockierung zum Synchronisieren des Zugriffs auf die Ressourcen nutzen. Weitere Informationen über diese Synchronisations-Primitive finden Sie unter Synchronisations-Datenstrukturen.
Die folgenden Abschnitte bieten einen kurzen Überblick über die jeweilige Komponente und deren Verwendung.
Bibliothek für parallele Muster
Die Parallel Patterns Library (PPL) bietet allgemeine Container und Algorithmen zum Ausführen der differenzierten Parallelität. Die PPL ermöglicht imperative Datenparallelität, indem sie parallele Algorithmen bereitstellt, die Berechnungen auf Collections oder auf Sets von Daten über die Ressourcen verteilen. Sie ermöglicht auch Task-Parallelität, indem sie Task-Objekte bereitstellt, die mehrere unabhängige Operationen über die Ressourcen verteilen.
Verwenden Sie die Parallel Patterns Library bei lokalen Berechnungen, die von der parallelen Ausführung profitieren können. Sie können zum Beispiel den Algorithmus concurrency::parallel_for verwenden, um eine bestehende forSchleife so zu transformieren, dass sie parallel arbeitet.
Weitere Informationen über die Parallel Patterns Library finden Sie unter Parallel Patterns Library (PPL).
Asynchrone Agents-Bibliothek
Die Asynchronous Agents Library (oder einfach Agents Library) bietet sowohl ein akteurbasiertes Programmiermodell als auch Schnittstellen zur Weitergabe von Nachrichten für grobkörnige Datenflow- und Pipeline-Aufgaben. Asynchrone Agents ermöglichen es Ihnen, die Latenz produktiv zu nutzen, indem Sie Arbeiten ausführen, während andere Komponenten auf die Daten warten.
Verwenden Sie die Agents Library, wenn Sie über mehrere Entitäten verfügen, die miteinander asynchron kommunizieren. Beispielsweise können Sie einen Agent erstellen, der die Daten aus einer Datei oder einer Netzwerkverbindung liest und anschließend die Schnittstellen der Meldungsübergabe verwendet, um diese Daten an einen anderen Agent zu senden.
Weitere Informationen über die Agents Library finden Sie unter Asynchronous Agents Library.
Aufgabenplanung
Der Taskplaner plant und koordiniert die Aufgaben zur Laufzeit. Der Taskplaner ist kooperativ und verwendet einen Arbeitsübernahme-Algorithmus, um die maximale Auslastung der Verarbeitungsressourcen zu erreichen.
Die Concurrency Runtime stellt einen Standardplaner bereit, sodass Sie keine Infrastrukturdetails verwalten müssen. Um die Qualitätsanforderungen Ihrer Anwendung zu erfüllen, können Sie jedoch auch Ihre eigene Planungsrichtlinie zur Verfügung stellen oder bestimmten Planern bestimmte Aufgaben zuordnen.
Weitere Informationen über den Task Scheduler finden Sie unter Task Scheduler.
Ressource Manager
Die Aufgabe des Ressourcen-Managers besteht darin, die Computerressourcen, wie beispielsweise Prozessoren und Arbeitsspeicher, zu verwalten. Der Ressourcen-Manager reagiert auf Arbeitslasten, die sich zur Laufzeit ändern, indem die Ressourcen dorthin zugewiesen werden, wo sie am effektivsten sind.
Der Ressourcen-Manager stellt eine Abstraktionsebene für die Computerressourcen dar und interagiert in erster Linie mit dem Aufgabenplaner. Obwohl Sie den Ressourcen-Manager zur Optimierung der Leistung Ihrer Bibliotheken und Anwendungen verwenden können, verwenden Sie in der Regel die Funktionalität, die von der Parallel Patterns Library, der Agents Library und dem Aufgabenplaner bereitgestellt wird. Diese Bibliotheken verwenden den Ressourcen-Manager, um die Ressourcen dynamisch neu zu verteilen, wenn sich die Arbeitslasten ändern.
C++ Lambda-Ausdrücke
Viele der Typen und Algorithmen, die von der Concurrency Runtime definiert werden, werden als C++-Vorlagen implementiert. Einige dieser Typen und Algorithmen nehmen als Parameter eine Routine an, die die Arbeit ausführt. Dieser Parameter kann eine Lambda-Funktion, ein Funktionsobjekt oder ein Funktionszeiger sein. Diese Entitäten werden auch als Work-Funktionen oder Work-Routinen bezeichnet.
Die Lambda-Ausdrücke sind eine wichtige neue Sprachfunktion in Visual C++, da sie eine kompakte Art und Weise zum Definieren von Arbeitsfunktionen für die Parallelverarbeitung bieten. Funktionsobjekte und Funktionszeiger ermöglichen Ihnen die Verwendung der Concurrency Runtime mit dem vorhandenen Code. Microsoft empfiehlt jedoch, Lambdaausdrücke beim Schreiben von neuem Code zu verwenden, da diese bezüglich der Sicherheit und Produktivität viele Vorteile bieten.
Das folgende Beispiel vergleicht die Syntax von Lambda-Funktionen, Funktionsobjekten und Funktionszeigern in mehreren Aufrufen des concurrency::parallel_for_each-Algorithmus. Jeder Aufruf von parallel_for_each verwendet eine andere Technik, um das Quadrat eines jeden Elements in einem std::array-Objekt zu berechnen.
// comparing-work-functions.cpp
// compile with: /EHsc
#include <ppl.h>
#include <array>
#include <iostream>
using namespace concurrency;
using namespace std;
// Function object (functor) class that computes the square of its input.
template<class Ty>
class SquareFunctor
{
public:
void operator()(Ty& n) const
{
n *= n;
}
};
// Function that computes the square of its input.
template<class Ty>
void square_function(Ty& n)
{
n *= n;
}
int wmain()
{
// Create an array object that contains 5 values.
array<int, 5> values = { 1, 2, 3, 4, 5 };
// Use a lambda function, a function object, and a function pointer to
// compute the square of each element of the array in parallel.
// Use a lambda function to square each element.
parallel_for_each(begin(values), end(values), [](int& n){n *= n;});
// Use a function object (functor) to square each element.
parallel_for_each(begin(values), end(values), SquareFunctor<int>());
// Use a function pointer to square each element.
parallel_for_each(begin(values), end(values), &square_function<int>);
// Print each element of the array to the console.
for_each(begin(values), end(values), [](int& n) {
wcout << n << endl;
});
}
Ausgabe
1
256
6561
65536
390625
Weitere Informationen über Lambda-Funktionen in C++ finden Sie unter Lambda-Ausdrücke.
Anforderungen
Die folgende Tabelle zeigt die Headerdateien, die jeder einzelnen Komponente der Concurrency Runtime zugeordnet sind:
| Komponente | Header Files |
|---|---|
| Parallel Patterns Library (PPL) | ppl.h concurrent_queue.h concurrent_vector.h |
| Asynchrone Agents-Bibliothek | agents.h |
| Aufgabenplanung | concrt.h |
| Ressource Manager | concrtrm.h |
Die Concurrency Runtime wird im Concurrency-Namespace deklariert. (Sie können auch concurrency verwenden, das ein Alias für diesen Namespace ist.) Der concurrency::details Namespace unterstützt das Framework Concurrency Runtime und ist nicht dafür gedacht, direkt in Ihrem Code verwendet zu werden.
Die Concurrency Runtime wird als Teil der C-Laufzeitbibliothek (CRT) bereitgestellt. Weitere Informationen darüber, wie Sie eine Anwendung erstellen, die den CRT verwendet, finden Sie unter CRT Library Features.