上下文

本文档介绍并发运行时中上下文的角色。 附加到计划程序的线程称为执行上下文(或只是上下文)concurrency::wait 函数和 concurrency::Context 类允许你控制上下文的行为。 使用 wait 函数在指定时间内暂停当前上下文。 当你需要更好地控制上下文何时阻止、取消阻止和暂停时,或者更好地控制你希望何时过度订阅当前上下文时,请使用 Context 类。

提示

并发运行时提供了一个默认计划程序,因此无需在应用程序中创建一个。 由于任务计划程序有助于优化应用程序的性能,如果你刚开始接触并发运行时,建议从使用并行模式库 (PPL)异步代理库开始。

wait 函数

concurrency::wait 函数通过协作使当前上下文暂停指定毫秒数的执行时间。 运行时使用暂停时间执行其他任务。 指定时间过后,运行时会重新计划执行上下文。 因此,wait 函数暂停当前上下文的时间可能会长于为 milliseconds 参数提供的值。

milliseconds 参数传递 0(零)会导致运行时暂停当前上下文,直到所有其他活动上下文都有机会执行工作。 这使你可以将某个任务对所有其他活动任务暂停。

示例

有关使用 wait 函数暂停当前上下文,因而允许其他上下文运行的示例,请参阅如何:使用计划组影响执行顺序

上下文类

concurrency::Context 类为执行上下文提供编程抽象,另外还提供两个重要功能:以协作方式阻止、取消阻止和暂停当前上下文的功能,以及过度订阅当前上下文的功能。

协作阻止

Context 类允许你阻止或暂停当前执行上下文。 在当前上下文因为资源不可用而无法继续时,阻止或暂停会非常有用。

concurrency::Context::Block 方法可阻止当前上下文。 阻止的上下文会暂停其处理资源,以便运行时可以执行其他任务。 concurrency::Context::Unblock 方法可取消阻止被阻止的上下文。 必须从与调用 Context::Block 的上下文不同的上下文调用 Context::Unblock 方法。 如果上下文尝试取消阻止自身,则运行时会引发 concurrency::context_self_unblock

若要以协作方式阻止和取消阻止上下文,通常需要调用 concurrency::Context::CurrentContext 以检索指向与当前线程关联的 Context 对象的指针,并保存结果。 随后调用 Context::Block 方法以阻止当前上下文。 稍后,从单独的上下文调用 Context::Unblock 以取消阻止被阻止的上下文。

必须匹配每个 Context::BlockContext::Unblock 调用对。 如果在依次调用 Context::BlockContext::Unblock 方法时没有针对其他方法的匹配调用,则运行时会引发 concurrency::context_unblock_unbalanced。 但是,在调用 Context::Unblock 之前,不必调用 Context::Block。 例如,如果一个上下文先调用 Context::Unblock,然后其他上下文对相同上下文调用 Context::Block,则该上下文会保持取消阻止状态。

concurrency::Context::Yield 方法可暂停执行,以便运行时可以执行其他任务,然后重新计划执行上下文。 调用 Context::Block 方法时,运行时不会重新计划上下文。

示例

有关使用 Context::BlockContext::UnblockContext::Yield 方法实现协作信号灯类的示例,请参阅如何:使用上下文类实现协作信号灯

过度订阅

默认计划程序会创建与可用硬件线程相同数量的线程。 可以使用过度订阅为给定硬件线程创建额外线程

对于计算密集型操作,过度订阅通常不会缩放,因为它引入了额外开销。 但是,对于延迟量较高的任务(例如从磁盘或网络连接读取数据),过度订阅可以提高某些应用程序的整体效率。

注意

仅从由并发运行时创建的线程中启用过度订阅。 当从不是由运行时创建的线程(包括主线程)进行调用时,过度订阅不起作用。

若要在当前上下文中启用过度订阅,请调用 concurrency::Context::Oversubscribe 方法,并将 _BeginOversubscription 参数设置为 true。 在并发运行时创建的线程上启用过度订阅时,会导致运行时创建一个额外线程。 所有需要过度订阅的任务都完成后,调用 Context::Oversubscribe 并将 _BeginOversubscription 参数设置为 false

可以从当前上下文中多次启用过度订阅,但禁用它的次数必须与启用次数相同。 过度订阅还可以嵌套;也就是说,由使用过度订阅的另一个任务创建的任务也可以过度订阅其上下文。 但是,如果嵌套任务及其父级都属于相同上下文,则只有最外部的 Context::Oversubscribe 调用才会创建额外线程。

注意

如果先禁用过度订阅再启用它,运行时会引发 concurrency::invalid_oversubscribe_operation

示例

有关使用过度订阅偏移从网络连接读取数据所导致的延迟的示例,请参阅如何:使用过度订阅偏移延迟

另请参阅

任务计划程序
如何:使用计划组影响执行顺序
如何:使用上下文类实现协作信号量
如何:使用过度订阅偏移延迟