Condividi tramite


Cenni preliminari sul runtime di concorrenza

Questo documento fornisce i cenni preliminari sul runtime di concorrenza. Illustra i vantaggi del runtime di concorrenza, quando usarlo e che modo i relativi componenti interagiscono tra loro e con il sistema operativo e le applicazioni.

Sezioni

Questo documento contiene le seguenti sezioni:

Cronologia di implementazione del runtime di concorrenza

In Visual Studio da 2010 a 2013 il runtime di concorrenza è stato incorporato all'interno di msvcr100.dll tramite msvcr120.dll. Quando si è verificato il refactoring UCRT in Visual Studio 2015, tale DLL è stata sottoposta a refactoring in tre parti:

  • ucrtbase.dll : API C, fornita in Windows 10 e di cui è stata eseguita la manutenzione tramite Windows Update

  • vcruntime140.dll : funzioni di supporto del compilatore e runtime EH, fornite tramite Visual Studio

  • concrt140.dll : runtime di concorrenza fornito tramite Visual Studio. Obbligatorio per contenitori paralleli e algoritmi, concurrency::parallel_forad esempio . Inoltre, la libreria STL richiede questa DLL in Windows XP per alimentare le primitive di sincronizzazione, perché Windows XP non dispone di variabili di condizione.

In Visual Studio 2015 e versioni successive, l'Utilità di pianificazione del runtime di concorrenza non è più l'utilità di pianificazione per la classe di attività e i tipi correlati in ppltasks. Tali tipi ora usano il pool di thread di Windows per migliorare le prestazioni e l'interoperabilità con le primitive di sincronizzazione di Windows.

Perché un runtime per la concorrenza è importante

Un runtime di concorrenza fornisce uniformità e prevedibilità alle applicazioni e ai componenti dell'applicazione eseguiti simultaneamente. Due esempi dei vantaggi del runtime di concorrenza sono la pianificazione delle attività cooperativa e il blocco cooperativo.

Il runtime di concorrenza usa un'utilità di pianificazione cooperativa che implementa un algoritmo di acquisizione del lavoro per distribuire il lavoro tra le risorse di elaborazione in modo efficiente. Si consideri, ad esempio, un'applicazione che dispone di due thread entrambi gestiti dallo stesso runtime. Se un thread termina l'attività pianificata, può scaricare il lavoro dall'altro thread. Questo meccanismo bilancia il carico di lavoro complessivo dell'applicazione.

Il runtime di concorrenza fornisce inoltre le primitive di sincronizzazione che usano il blocco cooperativo per sincronizzare l'accesso alle risorse. Si consideri, ad esempio, un'attività che deve avere accesso esclusivo a una risorsa condivisa. Mediante il blocco cooperativo, il runtime può usare il quantum rimanente per eseguire un'altra attività mentre la prima attività è in attesa della risorsa. Questo meccanismo consente il massimo utilizzo delle risorse di elaborazione.

[Torna all'inizio]

Architettura

Il runtime di concorrenza è diviso in quattro componenti: libreria PPL (Parallel Patterns Library), libreria di agenti asincroni, Utilità di pianificazione e Gestione risorse. Questi componenti risiedono tra il sistema operativo e le applicazioni. L'illustrazione seguente mostra come i componenti del runtime di concorrenza interagiscono tra il sistema operativo e le applicazioni:

Architettura del runtime di concorrenza

The Concurrency Runtime Architecture.

Importante

I componenti Utilità di pianificazione e Resource Manager non sono disponibili da un'app piattaforma UWP (Universal Windows Platform) (UWP) o quando usi la classe di attività o altri tipi in ppltasks.h.

Il runtime di concorrenza è altamente componibile, ovvero è possibile combinare le funzionalità esistenti per eseguire altre operazioni. Il runtime di concorrenza compone molte funzionalità, ad esempio gli algoritmi paralleli, dai componenti di livello inferiore.

Il runtime di concorrenza fornisce inoltre le primitive di sincronizzazione che usano il blocco cooperativo per sincronizzare l'accesso alle risorse. Per altre informazioni su queste primitive di sincronizzazione, vedere Synchronization Data Structures.For more information about these synchronization primitives, see Synchronization Data Structures.

Nelle sezioni seguenti vengono forniti alcuni cenni preliminari sui vantaggi di ogni componente e sul relativo uso.

Parallel Patterns Library

La libreria PPL (Parallel Patterns Library) fornisce contenitori e algoritmi di uso generale per l'esecuzione di un parallelismo accurato. Il PPL consente il parallelismo imperativo dei dati fornendo algoritmi paralleli che distribuiscono i calcoli nelle raccolte o nei set di dati tra le risorse di calcolo. Consente inoltre il parallelismo delle attività fornendo oggetti attività che distribuiscono più operazioni indipendenti tra le risorse di calcolo.

Usare la libreria PPL (Parallel Patterns Library) per i calcoli locali che possono trarre vantaggio dall'esecuzione parallela. Ad esempio, è possibile usare l'algoritmo concurrency::p arallel_for per trasformare un ciclo esistente for in modo che agisca in parallelo.

Per altre informazioni sulla libreria Parallel Patterns, vedere Parallel Patterns Library (PPL).

Libreria di agenti asincroni

La libreria degli agenti asincroni (o solo la libreria agenti) fornisce sia un modello di programmazione basato su attore che interfacce di passaggio di messaggi per attività di pipelining e flusso di dati con granularità grossolana. Gli agenti asincroni consentono di usare la latenza in modo produttivo eseguendo il lavoro come gli altri componenti in attesa dei dati.

Usare la libreria di agenti quando si dispone di più entità che comunicano tra loro in modo asincrono. È possibile, ad esempio, creare un agente che legge i dati da un file o da una connessione di rete e quindi usa le interfacce per il passaggio dei messaggi per inviare i dati a un altro agente.

Per altre informazioni sulla libreria agenti, vedere Libreria degli agenti asincroni.

Utilità di pianificazione

L'Utilità di pianificazione pianifica e coordina le attività in fase di esecuzione. L'Utilità di pianificazione è cooperativa e usa un algoritmo di acquisizione del lavoro per ottenere il massimo utilizzo delle risorse di elaborazione.

Il runtime di concorrenza fornisce un'utilità di pianificazione predefinita in modo da evitare di dover gestire i dettagli dell'infrastruttura. Tuttavia, per soddisfare le esigenze di qualità dell'applicazione, è anche possibile fornire criteri di pianificazione personalizzati o associare utilità di pianificazione specifiche a specifiche attività.

Per altre informazioni sull'Utilità di pianificazione, vedere Utilità di pianificazione.

Gestione risorse

Gestione risorse ha il ruolo di gestire le risorse di elaborazione, ad esempio processori e memoria. Gestione risorse risponde ai carichi di lavoro man mano che vengono modificati in fase di esecuzione assegnando le risorse dove possono risultare più efficaci.

Gestione risorse funge da astrazione sulle risorse di elaborazione e interagisce principalmente con l'Utilità di pianificazione. Sebbene sia possibile usare Gestione risorse per ottimizzare le prestazioni delle librerie e delle applicazioni, in genere vengono usate le funzionalità fornite dalla libreria PPL, dalla libreria di agenti e dall'Utilità di pianificazione. Tali librerie usano Gestione risorse per ribilanciare dinamicamente le risorse in base alla modifica dei carichi di lavoro.

[Torna all'inizio]

Espressioni lambda C++

Molti dei tipi e degli algoritmi definiti dal runtime di concorrenza vengono implementati come modelli C++. Alcuni di questi tipi e algoritmi accettano come parametro una routine che esegue il lavoro. Questo parametro può essere una funzione lambda, un oggetto funzione o un puntatore a funzione. Queste entità sono dette anche funzioni di lavoro o routine di lavoro.

Le espressioni lambda rappresentano una nuova e importante funzionalità del linguaggio di Visual C++ perché forniscono una modalità succinta per definire le funzioni lavoro per l'elaborazione in parallelo. Gli oggetti funzione e i puntatori a funzione consentono di usare il runtime di concorrenza con il codice esistente. Tuttavia, è consigliabile usare le espressioni lambda quando si scrive nuovo codice per i vantaggi offerti in termini di produttività e sicurezza.

Nell'esempio seguente viene confrontata la sintassi delle funzioni lambda, degli oggetti funzione e dei puntatori di funzione in più chiamate all'algoritmo concurrency::p arallel_for_each . Ogni chiamata a parallel_for_each usa una tecnica diversa per calcolare il quadrato di ogni elemento in un oggetto std::array .

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

Output

1
256
6561
65536
390625

Per altre informazioni sulle funzioni lambda in C++, vedere Espressioni lambda.

[Torna all'inizio]

Requisiti

Nella tabella seguente vengono mostrati i file di intestazione associati a ogni componente del runtime di concorrenza:

Componente File di intestazione
PPL (Parallel Patterns Library) ppl.h

concurrent_queue.h

concurrent_vector.h
Libreria di agenti asincroni agents.h
Utilità di pianificazione concrt.h
Gestione risorse concrtrm.h

Il runtime di concorrenza viene dichiarato nello spazio dei nomi Concurrency . È anche possibile usare la concorrenza, ovvero un alias per questo spazio dei nomi. Lo concurrency::details spazio dei nomi supporta il framework di runtime di concorrenza e non deve essere usato direttamente dal codice.

Il runtime di concorrenza viene fornito come parte della Libreria di runtime C (CRT). Per altre informazioni su come compilare un'applicazione che usa CRT, vedere Funzionalità della libreria CRT.

[Torna all'inizio]