Porównywanie struktur danych synchronizacji z Windows API
W tym temacie porównaliśmy zachowanie struktur danych synchronizacji udostępnianych przez środowisko uruchomieniowe współbieżności do tych dostarczonych przez interfejs API systemu Windows.
Struktury danych synchronizacji udostępniane przez środowisko uruchomieniowe współbieżności są zgodne z modelem współpracy wątkowości. W modelu wątków współpracy typy pierwotne synchronizacji jawnie dają zasoby przetwarzania innym wątkom. Różni się to od modelu wielowątkowego, w którym zasoby przetwarzania są przenoszone do innych wątków przez harmonogram sterowania lub system operacyjny.
critical_section
Klasa concurrency::critical_section przypomina strukturę systemu Windows CRITICAL_SECTION
, ponieważ może być używana tylko przez wątki jednego procesu. Aby uzyskać więcej informacji na temat krytycznych sekcji w interfejsie API systemu Windows, zobacz Sekcje krytyczne Obiekty.
Klasa reader_writer_lock
Klasa concurrency::reader_writer_lock przypomina blokady windows slim reader/writer (SRW). W poniższej tabeli opisano podobieństwa i różnice.
Funkcja | Klasa reader_writer_lock |
Blokada SRW |
---|---|---|
Non-reentrant | Tak | Tak |
Może podwyższyć poziom czytelnika do modułu zapisywania (obsługa uaktualniania) | Nie | Nie. |
Może obniżyć poziom zapisywania do czytelnika (obsługa obniżania poziomu) | Nie | Nie. |
Blokada preferencji zapisu | Tak | Nie. |
Dostęp FIFO do składników zapisywania | Tak | Nie. |
Aby uzyskać więcej informacji na temat blokad SRW, zobacz Slim Reader/Writer (SRW) Locks in the Platform SDK (Slim Reader/Writer( SRW) Locks in the Platform SDK (Slim Reader/Writer, SRW).
event
Klasa concurrency::event przypomina nienazwane zdarzenie ręcznego resetowania systemu Windows. event
Jednak obiekt zachowuje się kooperacyjnie, podczas gdy zdarzenie systemu Windows zachowuje się z góry. Aby uzyskać więcej informacji na temat zdarzeń systemu Windows, zobacz Event Objects (Obiekty zdarzeń).
Przykład
opis
Aby lepiej zrozumieć różnicę między klasą event
i zdarzeniami systemu Windows, rozważ poniższy przykład. W tym przykładzie harmonogram umożliwia utworzenie co najwyżej dwóch równoczesnych zadań, a następnie wywołanie dwóch podobnych funkcji korzystających z event
klasy i zdarzenia ręcznego resetowania systemu Windows. Każda funkcja najpierw tworzy kilka zadań, które oczekują na sygnał zdarzenia udostępnionego. Następnie każda funkcja zwraca uruchomione zadania, a następnie sygnalizuje zdarzenie. Następnie każda funkcja czeka na zasygnalizowane zdarzenie.
Kod
// 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();
}
Komentarze
W tym przykładzie są generowane następujące przykładowe dane wyjściowe:
Cooperative event:
Context 0: waiting on an event.
Context 1: waiting on an event.
Context 2: waiting on an event.
Context 3: waiting on an event.
Context 4: waiting on an event.
Setting the event.
Context 5: received the event.
Context 6: received the event.
Context 7: received the event.
Context 8: received the event.
Context 9: received the event.
Windows event:
Context 10: waiting on an event.
Context 11: waiting on an event.
Setting the event.
Context 12: received the event.
Context 14: waiting on an event.
Context 15: received the event.
Context 16: waiting on an event.
Context 17: received the event.
Context 18: waiting on an event.
Context 19: received the event.
Context 13: received the event.
event
Ponieważ klasa zachowuje się wspólnie, harmonogram może ponownie przydzielić zasoby przetwarzania do innego kontekstu, gdy zdarzenie oczekuje na wprowadzenie stanu zasygnalizowanego. W związku z tym większa praca jest osiągana przez wersję, która używa event
klasy . W wersji używającej zdarzeń systemu Windows każde zadanie oczekujące musi wprowadzić stan zasygnalizowany przed rozpoczęciem następnego zadania.
Aby uzyskać więcej informacji na temat zadań, zobacz Równoległość zadań.