Dela via


Översikt över Concurrency Runtime

Det här dokumentet innehåller en översikt över Concurrency Runtime. Den beskriver fördelarna med Concurrency Runtime, när den ska användas och hur dess komponenter interagerar med varandra och med operativsystemet och programmen.

Sektioner

Det här dokumentet innehåller följande avsnitt:

Implementeringshistorik för samtidighetsprogrammering

I Visual Studio 2010 till 2013 införlivades Concurrency Runtime i msvcr100.dll via msvcr120.dll. När UCRT-refaktoriseringen inträffade i Visual Studio 2015 omstrukturerades DLL:en till tre delar:

  • ucrtbase.dll – C API, levereras i Windows 10 och servas för tidigare versioner via Windows Update-

  • vcruntime140.dll – Stödfunktioner för kompilatorn och EH-körning, som levereras via Visual Studio

  • concrt140.dll – Concurrency Runtime, som levereras via Visual Studio. Krävs för parallella containrar och algoritmer som concurrency::parallel_for. Dessutom kräver STL denna DLL på Windows XP för att driva synkroniseringsprimitanter, eftersom Windows XP inte har villkorsvariabler.

I Visual Studio 2015 och senare är Concurrency Runtime Task Scheduler inte längre schemaläggaren för Task-klassen och relaterade typer i ppltasks.h. De här typerna använder nu Windows ThreadPool för bättre prestanda och samverkan med Windows-synkroniseringsprimit primitiver.

Varför en körtid för samtidighet är viktig

En körning för samtidighet ger enhetlighet och förutsägbarhet för program och programkomponenter som körs samtidigt. Två exempel på fördelarna med Concurrency Runtime är kooperativ aktivitetsschemaläggning och samarbetsblockering.

Concurrency Runtime använder en kooperativ schemaläggare som implementerar en arbetsstöldsalgoritm för att distribuera arbete effektivt mellan beräkningsresurser. Tänk dig till exempel en applikation som har två trådar som båda hanteras av samma körtid. Om en tråd har slutfört sin schemalagda uppgift kan den avlasta arbetet från den andra tråden. Den här mekanismen balanserar programmets övergripande arbetsbelastning.

Concurrency Runtime innehåller även synkroniseringsprimitiver som använder samarbetsblockering för att synkronisera åtkomst till resurser. Tänk dig till exempel en uppgift som måste ha exklusiv åtkomst till en delad resurs. Genom att blockera kooperativt kan körtiden använda det återstående kvantumet för att utföra en annan uppgift medan den första uppgiften väntar på resursen. Den här mekanismen främjar maximal användning av beräkningsresurser.

[Topp]

Arkitektur

Concurrency Runtime är indelad i fyra komponenter: PPL (Parallel Patterns Library), Asynchronous Agents Library, Task Scheduler och Resource Manager. Dessa komponenter finns mellan operativsystemet och programmen. Följande bild visar hur Concurrency Runtime-komponenterna interagerar mellan operativsystemet och programmen:

Arkitektur för samtidighetskörning

Samkörningsruntime-arkitekturen.

Viktigt!

Komponenterna Task Scheduler och Resource Manager är inte tillgängliga från en UWP-app (Universal Windows Platform) eller när du använder aktivitetsklassen eller andra typer i ppltasks.h.

Concurrency Runtime är mycket komposterbar, dvs. du kan kombinera befintliga funktioner för att göra mer. Concurrency Runtime består av många funktioner, till exempel parallella algoritmer, från komponenter på lägre nivå.

Concurrency Runtime innehåller även synkroniseringsprimitiver som använder samarbetsblockering för att synkronisera åtkomst till resurser. Mer information om dessa synkroniseringsprimitiver finns i Synkronisera datastrukturer.

Följande avsnitt ger en kort översikt över vad varje komponent tillhandahåller och när den ska användas.

Bibliotek för parallella mönster

PPL (Parallel Patterns Library) innehåller containrar och algoritmer för generell användning för att utföra detaljerad parallellitet. PPL möjliggör imperativ dataparallellitet genom att tillhandahålla parallella algoritmer som distribuerar beräkningar på samlingar eller på datauppsättningar mellan beräkningsresurser. Det möjliggör också uppgiftsparallellitet genom att tillhandahålla aktivitetsobjekt som distribuerar flera oberoende åtgärder mellan beräkningsresurser.

Använd biblioteket Parallella mönster när du har en lokal beräkning som kan dra nytta av parallell körning. Du kan till exempel använda algoritmen concurrency::parallel_for för att transformera en befintlig for loop för att den ska fungera parallellt.

För mer information om Parallel Patterns Library, se Parallel Patterns Library (PPL).

Asynkront agentbibliotek

Biblioteket asynkrona agenter (eller bara agentbiblioteket) innehåller både en aktörsbaserad programmeringsmodell och gränssnitt för meddelandeöverföring för grova dataflöden och pipelining-uppgifter. Med asynkrona agenter kan du använda svarstiden produktivt genom att utföra arbete medan andra komponenter väntar på data.

Använd agentbiblioteket när du har flera entiteter som kommunicerar asynkront med varandra. Du kan till exempel skapa en agent som läser data från en fil- eller nätverksanslutning och sedan använder meddelandet som skickar gränssnitt för att skicka dessa data till en annan agent.

Mer information om agentbiblioteket finns i Asynkront agentbibliotek.

Uppgiftsschemaläggare

Uppgiftsschemaläggaren schemalägger och samordnar uppgifter när de körs. Schemaläggaren är kooperativ och använder en algoritm för arbetsstöld för att uppnå maximal användning av processresurser.

Concurrency Runtime tillhandahåller en standardschemaläggare så att du inte behöver hantera infrastrukturinformation. Men för att uppfylla programmets kvalitetsbehov kan du också ange en egen schemaläggningsprincip eller associera specifika schemaläggare med specifika uppgifter.

Mer information om schemaläggaren finns i Schemaläggaren.

Resurshanterare

Rollen för Resource Manager är att hantera beräkningsresurser, till exempel processorer och minne. Resource Manager svarar på arbetsbelastningar när de ändras under körning genom att tilldela resurser dit de kan vara mest effektiva.

Resource Manager fungerar som en abstraktion över beräkningsresurser och interagerar främst med Schemaläggaren. Även om du kan använda Resource Manager för att finjustera prestandan för dina bibliotek och program använder du vanligtvis de funktioner som tillhandahålls av biblioteket parallella mönster, agentbiblioteket och schemaläggaren. De här biblioteken använder Resource Manager för att dynamiskt balansera om resurser när arbetsbelastningarna ändras.

[Topp]

C++ Lambda-uttryck

Många av de typer och algoritmer som definieras av Concurrency Runtime implementeras som C++-mallar. Vissa av dessa typer och algoritmer tar som en parameter en rutin som utför arbete. Den här parametern kan vara en lambda-funktion, ett funktionsobjekt eller en funktionspekare. Dessa entiteter kallas även för arbetsfunktioner eller arbetsrutiner.

Lambda-uttryck är en viktig ny Visual C++-språkfunktion eftersom de är ett kortfattat sätt att definiera arbetsfunktioner för parallell bearbetning. Med funktionsobjekt och funktionspekare kan du använda Concurrency Runtime med din befintliga kod. Vi rekommenderar dock att du använder lambda-uttryck när du skriver ny kod på grund av de säkerhets- och produktivitetsfördelar som de ger.

I följande exempel jämförs syntaxen för lambda-funktioner, funktionsobjekt och funktionspekare i flera anrop av algoritmen concurrency::parallel_for_each. Varje anrop till parallel_for_each använder en annan teknik för att beräkna kvadraten för varje element i ett std::array-objekt .

// 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;
   });
}

Resultat

1
256
6561
65536
390625

Mer information om lambda-funktioner i C++finns i Lambda-uttryck.

[Topp]

Kravspecifikation

I följande tabell visas huvudfilerna som är associerade med varje komponent i Concurrency Runtime:

Komponent Rubrikfiler
PPL (Parallel Patterns Library) ppl.h

concurrent_queue.h

concurrent_vector.h
Asynkront agentbibliotek agents.h
Uppgiftsschemaläggare concrt.h
Resurshanterare concrtrm.h

Concurrency Runtime deklareras i Concurrency-namnutrymmet. (Du kan också använda samtidighet, vilket är ett alias för det här namnområdet.) Namnområdet concurrency::details stöder Concurrency Runtime-ramverket och är inte avsett att användas direkt från koden.

Concurrency Runtime tillhandahålls som en del av C Runtime Library (CRT). Mer information om hur du skapar ett program som använder CRT finns i CRT-biblioteksfunktioner.

[Topp]