将并发运行时提供的同步数据结构的行为与 Windows API 提供的同步数据结构的行为进行比较。
并发运行时提供的同步数据结构遵循协作线程模型。 在协作线程模型中,同步基元显式将其处理资源传递给其他线程。 这与抢占式线程模型不同,其中处理资源由控制调度程序或操作系统转移到其他线程。
critical_section
concurrency::critical_section 类类似于 Windows CRITICAL_SECTION 结构,因为它只能由一个进程的线程使用。
reader_writer_lock
concurrency::reader_writer_lock 类类似于 Windows 精简读取器/编写器 (SRW) 锁。
event
concurrency::event 类类似于未命名的 Windows 手动重置事件。 不过,event 对象以协作方式运行,而 Windows 事件以抢占方式运行。
示例说明
若要更好地了解 event 类和 Windows 事件之间的区别,请考虑以下示例。 此示例使调度程序最多可以同时创建两个任务,然后调用两个使用 event 类和 Windows 手动重置事件的类似函数。 每个函数首先创建几个等待共享事件发出信号的任务。 然后,每个函数都会转移到正在运行的任务并向事件发出信号。 之后,每个函数等待信号事件。
// 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();
}
输出如下:
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 类以协作方式运行,因此当事件等待进入信号状态时,调度程序可以将处理资源重新分配给另一个上下文。 因此,更多的工作将由使用 event 类的版本完成。 在使用 Windows 事件的版本中,每个等待任务必须在下一个任务开始之前进入信号状态。