将同步数据结构与 Windows API 进行比较
本主题将并发运行时提供的同步数据结构的行为与 Windows API 提供的同步数据结构的行为进行比较。
并发运行时提供的同步数据结构遵循协作线程模型。 在协作线程模型中,同步基元显式将其处理资源传递给其他线程。 这与抢占式线程模型不同,其中处理资源由控制调度程序或操作系统转移到其他线程。
critical_section
concurrency::critical_section 类类似于 Windows CRITICAL_SECTION
结构,因为它只能由一个进程的线程使用。 有关 Windows API 中关键部分的详细信息,请参阅关键部分对象。
reader_writer_lock
concurrency::reader_writer_lock 类类似于 Windows 精简读取器/编写器 (SRW) 锁。 下表说明了相似性和差异。
功能 | reader_writer_lock 类 |
SRW 锁 |
---|---|---|
不可重入 | 是 | 是 |
可以将读取器提升为编写器(升级支持) | 否 | 否 |
可以将编写器降级为读取器(降级支持) | 否 | 否 |
写入首选项锁 | 是 | 否 |
FIFO 对编写器的访问权限 | 是 | 否 |
有关 SRW 锁的详细信息,请参阅平台 SDK 中的精简读取器/编写器 (SRW) 锁。
event
concurrency::event 类类似于未命名的 Windows 手动重置事件。 不过,event
对象以协作方式运行,而 Windows 事件以抢占方式运行。 有关 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 事件的版本中,每个等待任务必须在下一个任务开始之前进入信号状态。
有关任务的详细信息,请参阅任务并行。