Comparaison de structures de données de synchronisation avec l'API Windows
Cette rubrique compare le comportement des structures de données de synchronisation fournies par le runtime d'accès concurrentiel à celles fournies par l'API Windows.
Les structures de données de synchronisation fournies par le runtime d'accès concurrentiel suivent le modèle de thread coopératif. Dans le modèle de thread coopératif, les primitives de synchronisation cèdent explicitement leurs ressources de traitement à d'autres threads. Cela diffère du modèle de thread préemptif, selon lequel les ressources de traitement sont transférées à d'autres threads par le système d'exploitation ou le planificateur de contrôle.
critical_section
La classe concurrency::critical_section s'apparente à la structure CRITICAL_SECTION Windows, car elle peut uniquement être utilisée par les threads d'un seul processus. Pour plus d'informations sur les sections critiques dans l'API Windows, consultez Objets de section critique.
reader_writer_lock
La classe concurrency::reader_writer_lock s'apparente aux verrous SRW (Slim Reader/Writer) de Windows. Le tableau suivant explique quelles sont les similarités et les différences.
Fonctionnalité |
reader_writer_lock |
Verrou SRW |
---|---|---|
Non réentrant |
Oui |
Oui |
Peut promouvoir un lecteur en enregistreur (prise en charge de la mise à niveau) |
Non |
Non |
Peut rétrograder un enregistreur en lecteur (prise en charge de la rétrogradation) |
Non |
Non |
Verrou à préférence d'écriture |
Oui |
Non |
Accès FIFO aux enregistreurs |
Oui |
Non |
Pour plus d'informations sur les verrous SRW, consultez la rubrique sur les verrous SRW (Slim Reader/Writer) dans le Kit de développement Platform SDK.
event
La classe concurrency::event s'apparente à un événement Windows à réinitialisation manuelle sans nom. Toutefois, un objet event se comporte de manière coopérative, alors qu'un événement Windows se comporte de manière préemptive. Pour plus d'informations sur les événements Windows, consultez Objets événements.
Exemple
Description
Pour mieux comprendre la différence entre la classe event et les événements Windows, considérez l'exemple suivant. Cet exemple permet au planificateur de créer au plus deux tâches simultanées, puis il appelle deux fonctions semblables qui utilisent la classe event et un événement Windows à réinitialisation manuelle. Chaque fonction crée d'abord plusieurs tâches qui attendent qu'un événement partagé soit signalé. Chaque fonction cède ensuite aux tâches en cours d'exécution, puis signale l'événement. Chaque fonction attend ensuite l'événement signalé.
Code
// event-comparison.cpp
// compile with: /EHsc
#include <windows.h>
#include <concrtrm.h>
#include <ppl.h>
#include <iostream>
#include <sstream>
using namespace concurrency;
using namespace std;
// Demonstrates the usage of cooperative events.
void RunCooperativeEvents()
{
// An event object.
event e;
// Create a task group and execute five tasks that wait for
// the event to be set.
task_group tasks;
for (int i = 0; i < 5; ++i)
{
tasks.run([&] {
// Print a message before waiting on the event.
wstringstream ss;
ss << L"\t\tContext " << GetExecutionContextId()
<< L": waiting on an event." << endl;
wcout << ss.str();
// Wait for the event to be set.
e.wait();
// Print a message after the event is set.
ss = wstringstream();
ss << L"\t\tContext " << GetExecutionContextId()
<< L": received the event." << endl;
wcout << ss.str();
});
}
// Wait a sufficient amount of time for all tasks to enter
// the waiting state.
Sleep(1000L);
// Set the event.
wstringstream ss;
ss << L"\tSetting the event." << endl;
wcout << ss.str();
e.set();
// Wait for all tasks to complete.
tasks.wait();
}
// Demonstrates the usage of preemptive events.
void RunWindowsEvents()
{
// A Windows event object.
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("Windows Event"));
// Create a task group and execute five tasks that wait for
// the event to be set.
task_group tasks;
for (int i = 0; i < 5; ++i)
{
tasks.run([&] {
// Print a message before waiting on the event.
wstringstream ss;
ss << L"\t\tContext " << GetExecutionContextId()
<< L": waiting on an event." << endl;
wcout << ss.str();
// Wait for the event to be set.
WaitForSingleObject(hEvent, INFINITE);
// Print a message after the event is set.
ss = wstringstream();
ss << L"\t\tContext " << GetExecutionContextId()
<< L": received the event." << endl;
wcout << ss.str();
});
}
// Wait a sufficient amount of time for all tasks to enter
// the waiting state.
Sleep(1000L);
// Set the event.
wstringstream ss;
ss << L"\tSetting the event." << endl;
wcout << ss.str();
SetEvent(hEvent);
// Wait for all tasks to complete.
tasks.wait();
// Close the event handle.
CloseHandle(hEvent);
}
int wmain()
{
// Create a scheduler policy that allows up to two
// simultaneous tasks.
SchedulerPolicy policy(1, MaxConcurrency, 2);
// Attach the policy to the current scheduler.
CurrentScheduler::Create(policy);
wcout << L"Cooperative event:" << endl;
RunCooperativeEvents();
wcout << L"Windows event:" << endl;
RunWindowsEvents();
}
Commentaires
Cet exemple génère l'exemple de sortie suivant :
Étant donné que la classe event se comporte de manière coopérative, le planificateur peut réaffecter les ressources de traitement à un autre contexte lorsqu'un événement attend de passer à l'état signalé. Par conséquent, davantage de travail est accompli par la version qui utilise la classe event. Dans la version qui utilise des événements Windows, chaque tâche en attente doit passer à l'état signalé avant que la tâche suivante soit démarrée.
Pour plus d'informations sur les tâches, consultez Parallélisme des tâches (runtime d'accès concurrentiel).
Voir aussi
Référence
Verrous légers (SRW) de lecture/écriture léger