当前位置: 首页 > news >正文

第二季企业网站开发可以建网站的公司

第二季企业网站开发,可以建网站的公司,做网站需要哪些方面的支出,宁波设计公司有哪些将工作卸载到 Windows 线程池 协同例程与任何其他函数的类似之处在于#xff0c;调用方将会阻塞到某个函数向其返回了执行为止。 另外#xff0c;协同例程返回的第一个机会是第一个 co_await、co_return 或 co_yield。 因此#xff0c;在协同例程中执行受计算限制的工作之…将工作卸载到 Windows 线程池 协同例程与任何其他函数的类似之处在于调用方将会阻塞到某个函数向其返回了执行为止。 另外协同例程返回的第一个机会是第一个 co_await、co_return 或 co_yield。 因此在协同例程中执行受计算限制的工作之前需要将执行返回给调用方换句话说引入暂停点使调用方不被阻塞。 如果还没有对其他某个操作运行 co_await 来做到这一点则可以对 winrt::resume_background 函数运行 co_await。 这会将控制权返回给调用方然后立即在某个线程池线程上恢复执行。 实现中使用的线程池是底层 Windows 线程池因此具有极高的效率。 IAsyncOperationuint32_t DoWorkOnThreadPoolAsync() {co_await winrt::resume_background(); // Return control; resume on thread pool.uint32_t result;for (uint32_t y 0; y height; y)for (uint32_t x 0; x width; x){// Do compute-bound work here.}co_return result; }编程时仔细考虑线程相关性 该方案继续对上一个方案进行扩展。 你已将一些工作卸载到线程池但希望在用户界面 (UI) 中显示进度。 IAsyncAction DoWorkAsync(TextBlock textblock) {co_await winrt::resume_background();// Do compute-bound work here.textblock.Text(LDone!); // Error: TextBlock has thread affinity. }上述代码抛出一个 winrt::hresult_wrong_thread 异常因为必须从创建 TextBlock 的线程即 UI 线程更新 TextBlock。 一种解决方案是捕获最初调用协同例程的线程上下文。 为此请实例化 winrt::apartment_context 对象执行后台工作然后对 apartment_context 运行 co_await 以切回到调用上下文。 IAsyncAction DoWorkAsync(TextBlock textblock) {winrt::apartment_context ui_thread; // Capture calling context.co_await winrt::resume_background();// Do compute-bound work here.co_await ui_thread; // Switch back to calling context.textblock.Text(LDone!); // Ok if we really were called from the UI thread. }只要上面的协同例程是从创建 TextBlock 的 UI 线程调用的这种方法是可行的。 在应用中有很多时候都是可以保证这一点的。 若要通过某种更通用的解决方案来更新 UI包括不确定调用线程的情况可以对 winrt::resume_foreground 函数运行 co_await以切换到特定的前台线程。 在以下代码示例中我们通过传递与 TextBlock 关联的调度程序对象通过访问其 Dispatcher 属性来指定前台线程。 winrt::resume_foreground 实现对该调度程序对象调用 CoreDispatcher.RunAsync以执行协同例程中该调度程序对象之后的工作。 IAsyncAction DoWorkAsync(TextBlock textblock) {co_await winrt::resume_background();// Do compute-bound work here.// Switch to the foreground thread associated with textblock.co_await winrt::resume_foreground(textblock.Dispatcher());textblock.Text(LDone!); // Guaranteed to work. }winrt::resume_foreground 函数采用可选的优先级参数。 如果使用该参数则可以使用上面所示的模式。 如果不使用则可以选择将 co_await winrt::resume_foreground(someDispatcherObject); 简化为 co_await someDispatcherObject;。 协同例程中的执行上下文、恢复和切换 概括地说在协同例程中某个暂停点之后原始执行线程可能会消失而恢复可能会在任何线程上发生换而言之任何线程都可以针对异步操作调用 Completed 方法。 但是如果对四个 Windows 运行时异步操作类型 (IAsyncXxx) 中的任何一个运行 co_await则 C/WinRT 会在运行 co_await 时捕获调用上下文。 另外它可以当延续操作恢复时你仍处于该上下文中。 为此C/WinRT 会检查你是否已进入调用上下文如果没有则切换到该上下文。 如果在运行 co_await 之前你处于单线程单元 (STA) 线程中则运行之后你仍处于相同的线程中如果在运行 co_await 之前你处于多线程单元 (MTA) 线程中则运行之后你将处于不同的线程中。 IAsyncAction ProcessFeedAsync() {Uri rssFeedUri{ Lhttps://blogs.windows.com/feed };SyndicationClient syndicationClient;// The thread context at this point is captured...SyndicationFeed syndicationFeed{ co_await syndicationClient.RetrieveFeedAsync(rssFeedUri) };// ...and is restored at this point. }可以依赖此行为的原因在于C/WinRT 提供相应的代码使这些 Windows 运行时异步操作类型能够适应 C 协同例程语言支持这些代码片段称为等待适配器。 C/WinRT 中剩余的可等待类型只是一些线程池包装器和/或帮助器因此它们会在线程池中完成。 using namespace std::chrono_literals; IAsyncOperationint return_123_after_5s() {// No matter what the thread context is at this point...co_await 5s;// ...were on the thread pool at this point.co_return 123; }如果对其他某个类型运行 co_await即使是在 C/WinRT 协同例程实现中则另一个库会提供适配器你需要了解这些适配器在恢复和上下文方面的作用。 为了尽量减少上下文切换次数可以使用本主题所述的某些方法。 让我们看看该操作的几个图示。 以下伪代码示例演示了一个事件处理程序的大纲。该处理程序调用 Windows 运行时 API 来加载图像切换到后台线程来处理该图像然后返回到 UI 线程以在 UI 中显示该图像。 IAsyncAction MainPage::ClickHandler(IInspectable /* sender */, RoutedEventArgs /* args */) {// We begin in the UI context.// Call StorageFile::OpenAsync to load an image file.// The call to OpenAsync occurred on a background thread, but C/WinRT has restored us to the UI thread by this point.co_await winrt::resume_background();// Were now on a background thread.// Process the image.co_await winrt::resume_foreground(this-Dispatcher());// Were back on MainPages UI thread.// Display the image in the UI. }在此方案中调用 StorageFile::OpenAsync 会使效率略微下降。 恢复时有必要将上下文切换到后台线程这样处理程序便可以将执行返回给调用方然后 C/WinRT 会还原 UI 线程上下文。 但是在此情况下在我们即将更新 UI 之前没有必要处于 UI 线程中。 在调用 winrt::resume_background 之前调用的 Windows 运行时 API 越多发生的不必要往返上下文切换也越多。 解决方法是在此之前不要调用任何 Windows 运行时 API。 将所有此类调用移到 winrt::resume_background 的后面。 IAsyncAction MainPage::ClickHandler(IInspectable /* sender */, RoutedEventArgs /* args */) {// We begin in the UI context.co_await winrt::resume_background();// Were now on a background thread.// Call StorageFile::OpenAsync to load an image file.// Process the image.co_await winrt::resume_foreground(this-Dispatcher());// Were back on MainPages UI thread.// Display the image in the UI. }如果需要提前执行某些调用可以编写自己的 await 适配器。 例如若要运行 co_await 以便在完成异步操作所在的同一线程上进行恢复因此不会发生上下文切换可以先编写如下所示的 await 适配器。 以下代码示例仅用于培训目的可帮助你开始了解 await 适配器的工作原理。 若要在自己的基代码中使用此方法我们建议你开发并测试自己的 await 适配器结构。 例如可以编写 complete_on_any、complete_on_current 和 complete_on(dispatcher) 。 另请考虑将这些结构设置为使用 IAsyncXxx 类型作为模板参数的模板。 struct no_switch {no_switch(Windows::Foundation::IAsyncAction const async) : m_async(async){}bool await_ready() const{return m_async.Status() Windows::Foundation::AsyncStatus::Completed;}void await_suspend(std::experimental::coroutine_handle handle) const{m_async.Completed([handle](Windows::Foundation::IAsyncAction const /* asyncInfo */, Windows::Foundation::AsyncStatus const /* asyncStatus */){handle();});}auto await_resume() const{return m_async.GetResults();}private:Windows::Foundation::IAsyncAction const m_async; };若要了解如何使用 no_switch await 适配器首先需要知道当 C 编译器遇到 co_await 表达式时它会查找名为 await_ready、await_suspend 和 await_resume 的函数。 C/WinRT 库提供了这些函数使你在默认情况下能够获得合理行为如下所示。 IAsyncAction async{ ProcessFeedAsync() }; co_await async;若要使用 no_switch await 适配器只需将该 co_await 表达式的类型从 IAsyncXxx 更改为 no_switch如下所示。 IAsyncAction async{ ProcessFeedAsync() }; co_await static_castno_switch(async);然后C 编译器不会查找与 IAsyncXxx 匹配的三个 await_xxx 函数而是查找与 no_switch 匹配的函数。 深入了解 winrt::resume_foreground 从 C/WinRT 2.0 开始winrt::resume_foreground 函数会暂停即使是从调度程序线程来调用它在以前的版本中它可能会在某些情况下引入死锁因为它暂停的前提是尚未位于调度程序线程上。 当前的行为意味着你可以依赖于堆栈展开和进行的重新排队这对于系统稳定很重要尤其是在低级别系统代码中。 在上面的编程时仔细考虑线程相关性部分列出的最后的代码演示了如何在后台线程上执行某些复杂的计算然后切换到相应的 UI 线程以便更新用户界面 (UI)。 下面是 winrt::resume_foreground 的具体代码。 auto resume_foreground(...) noexcept {struct awaitable{bool await_ready() const{return false; // Queue without waiting.// return m_dispatcher.HasThreadAccess(); // The C/WinRT 1.0 implementation.}void await_resume() const {}void await_suspend(coroutine_handle handle) const { ... }};return awaitable{ ... }; };这种当前行为与过去行为的对比类似于 Win32 应用程序开发过程中出现的 PostMessage 和 SendMessage 之间的差异。 PostMessage 先将工作排队然后在不等待工作完成的情况下展开堆栈。 堆栈展开有时候很重要。 winrt::resume_foreground 函数一开始也只支持在 Windows 10 之前引入的 CoreDispatcher绑定到 CoreWindow。 自那以后我们引入了更灵活高效的调度程序DispatcherQueue。 你可以创建适合自己使用的 DispatcherQueue。 让我们考虑一下这个简单的控制台应用程序。 using namespace Windows::System;winrt::fire_and_forget RunAsync(DispatcherQueue queue);int main() {auto controller{ DispatcherQueueController::CreateOnDedicatedThread() };RunAsync(controller.DispatcherQueue());getchar(); }上面的示例在专用线程上创建一个队列包含在控制器中然后将控制器传递给协同程序。 协同程序可以使用队列在专用线程上等待先暂停再继续。 DispatcherQueue 的另一常见用法是在传统桌面或 Win32 应用的当前 UI 线程上创建一个队列。 DispatcherQueueController CreateDispatcherQueueController() {DispatcherQueueOptions options{sizeof(DispatcherQueueOptions),DQTYPE_THREAD_CURRENT,DQTAT_COM_STA};ABI::Windows::System::IDispatcherQueueController* ptr{};winrt::check_hresult(CreateDispatcherQueueController(options, ptr));return { ptr, take_ownership_from_abi }; }上面的代码演示了如何调用 Win32 函数并将其纳入 C/WinRT 项目中方法是直接调用 Win32 样式的 CreateDispatcherQueueController 函数来创建控制器然后将生成的队列控制器的所有权以 WinRT 对象形式移交给调用方。 这也正是你能够在现有的 Petzold 样式 Win32 桌面应用程序上为高效无缝排队提供支持的方式。 winrt::fire_and_forget RunAsync(DispatcherQueue queue);int main() {Window window;auto controller{ CreateDispatcherQueueController() };RunAsync(controller.DispatcherQueue());MSG message;while (GetMessage(message, nullptr, 0, 0)){DispatchMessage(message);} }上面这个简单的 main 函数一开始就创建一个窗口。 你可以想象一下这样会注册一个 window 类然后调用 CreateWindow 来创建顶级桌面窗口。 然后调用 CreateDispatcherQueueController 函数来创建队列控制器再通过该控制器拥有的调度程序队列调用某个协同程序。 然后进入传统的消息泵在其中的此线程上自然而然地恢复协同程序。 然后你可以回到协同程序所在的位置在应用程序中完成异步的或基于消息的工作流。 winrt::fire_and_forget RunAsync(DispatcherQueue queue) {... // Begin on the calling thread...co_await winrt::resume_foreground(queue);... // ...resume on the dispatcher thread. }调用 winrt::resume_foreground 时会始终先排队然后展开堆栈。 也可选择设置恢复优先级。 winrt::fire_and_forget RunAsync(DispatcherQueue queue) {...co_await winrt::resume_foreground(queue, DispatcherQueuePriority::High);... }或者使用默认的排队顺序。 ... #include winrt/Windows.System.h using namespace Windows::System; ... winrt::fire_and_forget RunAsync(DispatcherQueue queue) {...co_await queue;... }如上所示请确保包含要 co_await 的类型的命名空间的投影标头。 例如 Windows::UI::Core::CoreDispatcher、Windows::System::DispatcherQueue 或 Microsoft::UI::Dispatching::DispatcherQueue 。 或者检测队列关闭情况并对其进行适当处理如以下示例所示。 winrt::fire_and_forget RunAsync(DispatcherQueue queue) {...if (co_await queue){... // Resume on dispatcher thread.}else{... // Still on calling thread.} }co_await 表达式返回 true表明会在调度程序线程上进行恢复。 换而言之该排队操作是成功的。 与之相反的是返回 false这表明执行仍保留在调用线程上因为队列的控制器关闭再也不能处理队列请求。 因此在将 C/WinRT 与协同程序配合使用的情况下尤其是在进行一些传统的 Petzold 样式桌面应用程序开发的情况下你拥有很大的控制权限。 取消异步操作和取消回调 使用 Windows 运行时的异步编程功能可以取消正在进行的异步操作或运算。 以下示例调用 StorageFolder::GetFilesAsync 来检索可能较大的文件集合并将生成的异步操作对象存储在数据成员中。 用户可以选择取消该操作。 // MainPage.xaml ... Button x:NameworkButton ClickOnWorkWork/Button Button x:NamecancelButton ClickOnCancelCancel/Button ...// MainPage.h ... #include winrt/Windows.Foundation.h #include winrt/Windows.Foundation.Collections.h #include winrt/Windows.Storage.Search.husing namespace winrt; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::Storage; using namespace Windows::Storage::Search; using namespace Windows::UI::Xaml; ... struct MainPage : MainPageTMainPage {MainPage(){InitializeComponent();}IAsyncAction OnWork(IInspectable /* sender */, RoutedEventArgs /* args */){workButton().Content(winrt::box_value(LWorking...));// Enable the Pictures Library capability in the app manifest file.StorageFolder picturesLibrary{ KnownFolders::PicturesLibrary() };m_async picturesLibrary.GetFilesAsync(CommonFileQuery::OrderByDate, 0, 1000);IVectorViewStorageFile filesInFolder{ co_await m_async };workButton().Content(box_value(LDone!));// Process the files in some way.}void OnCancel(IInspectable const /* sender */, RoutedEventArgs const /* args */){if (m_async.Status() ! AsyncStatus::Completed){m_async.Cancel();workButton().Content(winrt::box_value(LCanceled));}}private:IAsyncOperation::IVectorViewStorageFile m_async; }; ...让我们通过一个简单的示例开始了解取消的实现端。 // main.cpp #include iostream #include winrt/Windows.Foundation.husing namespace winrt; using namespace Windows::Foundation; using namespace std::chrono_literals;IAsyncAction ImplicitCancelationAsync() {while (true){std::cout ImplicitCancelationAsync: do some work for 1 second std::endl;co_await 1s;} }IAsyncAction MainCoroutineAsync() {auto implicit_cancelation{ ImplicitCancelationAsync() };co_await 3s;implicit_cancelation.Cancel(); }int main() {winrt::init_apartment();MainCoroutineAsync().get(); }如果运行上述示例则你会看到ImplicitCancellationAsync 在三秒钟内每秒输出一条消息然后它会由于执行了取消操作而自动终止。 之所以此行为是可行的是因为在遇到 co_await 表达式时协同例程会检查它是否已取消。 如果已取消则它会短路掉否则它会像正常情况下一样暂停。 当然取消也可以在协同例程暂停时发生。 仅当协同例程恢复或者遇到另一个 co_await 时它才会检查取消状态。 问题在于在响应取消时可能会出现过于粗糙粒度的延迟。 因此另一种做法是从协同例程内部显式轮询取消。 使用以下列表中的代码更新上述示例。 在此新示例中ExplicitCancellationAsync 检索 winrt::get_cancellation_token 函数返回的对象并使用该对象定期检查是否已取消协同例程。 只要尚未取消协同例程就会无限循环一旦取消循环和函数就会正常退出。 结果与前一个示例相同不过在此示例中退出是显式发生的并且受控。 IAsyncAction ExplicitCancelationAsync() {auto cancelation_token{ co_await winrt::get_cancellation_token() };while (!cancelation_token()){std::cout ExplicitCancelationAsync: do some work for 1 second std::endl;co_await 1s;} }IAsyncAction MainCoroutineAsync() {auto explicit_cancelation{ ExplicitCancelationAsync() };co_await 3s;explicit_cancelation.Cancel(); } ...等待 winrt::get_cancellation_token 时会使用协同例程代表你生成的 IAsyncAction 信息检索取消标记。 可以针对该标记使用函数调用运算符以查询取消状态实质上是轮询取消。 如果执行某项计算资源受限的操作或循环访问大型集合则这是一种合理的方法。 注册取消回调 Windows 运行时的取消不会自动流向其他异步对象。 但是可以注册取消回调这是 Windows SDK 版本 10.0.17763.0Windows 10 版本 1809中引入的功能。 这是一种先发性的挂钩可据此传播取消以及与现有的并发库集成。 在以下代码示例中NestedCoroutineAsync 将执行工作但其中不包含特殊的取消逻辑。 CancellationPropagatorAsync 实质上是嵌套协同例程中的一个包装器该包装器提前转发取消。 // main.cpp #include iostream #include winrt/Windows.Foundation.husing namespace winrt; using namespace Windows::Foundation; using namespace std::chrono_literals;IAsyncAction NestedCoroutineAsync() {while (true){std::cout NestedCoroutineAsync: do some work for 1 second std::endl;co_await 1s;} }IAsyncAction CancelationPropagatorAsync() {auto cancelation_token{ co_await winrt::get_cancellation_token() };auto nested_coroutine{ NestedCoroutineAsync() };cancelation_token.callback([]{nested_coroutine.Cancel();});co_await nested_coroutine; }IAsyncAction MainCoroutineAsync() {auto cancelation_propagator{ CancelationPropagatorAsync() };co_await 3s;cancelation_propagator.Cancel(); }int main() {winrt::init_apartment();MainCoroutineAsync().get(); }CancellationPropagatorAsync 为自身的取消回调注册一个 lambda 函数然后等待此时会暂停嵌套的工作完成。 如果 CancellationPropagatorAsync 已取消则会将取消传播到嵌套的协同例程。 无需轮询取消取消不会无限期阻塞。 此机制足够灵活使用它可以与完全不了解 C/WinRT 的协同例程或并发库互操作。 报告进度 如果协同例程返回 IAsyncActionWithProgress 或 IAsyncOperationWithProgress则你可以检索 winrt::get_progress_token 函数返回的对象并使用该对象将进度报告给进度处理程序。 下面是代码示例。 // main.cpp #include iostream #include winrt/Windows.Foundation.husing namespace winrt; using namespace Windows::Foundation; using namespace std::chrono_literals;IAsyncOperationWithProgressdouble, double CalcPiTo5DPs() {auto progress{ co_await winrt::get_progress_token() };co_await 1s;double pi_so_far{ 3.1 };progress.set_result(pi_so_far);progress(0.2);co_await 1s;pi_so_far 4.e-2;progress.set_result(pi_so_far);progress(0.4);co_await 1s;pi_so_far 1.e-3;progress.set_result(pi_so_far);progress(0.6);co_await 1s;pi_so_far 5.e-4;progress.set_result(pi_so_far);progress(0.8);co_await 1s;pi_so_far 9.e-5;progress.set_result(pi_so_far);progress(1.0);co_return pi_so_far; }IAsyncAction DoMath() {auto async_op_with_progress{ CalcPiTo5DPs() };async_op_with_progress.Progress([](auto const sender, double progress){std::wcout LCalcPiTo5DPs() reports progress: progress L. LValue so far: sender.GetResults() std::endl;});double pi{ co_await async_op_with_progress };std::wcout LCalcPiTo5DPs() is complete ! std::endl;std::wcout LPi is approx.: pi std::endl; }int main() {winrt::init_apartment();DoMath().get(); }若要报告进度请调用以进度值作为参数的进度标记。 若要设置临时结果请对进度标记使用 set_result() 方法。 报告临时结果需要 C/WinRT 版本 2.0.210309.3 或更高版本。 上面的示例选择为每个进度报告都设置一个临时结果。 可以选择随时报告临时结果如果有。 它不需要加上进度报告。 对一个异步操作或运算实现多个完成处理程序是错误的做法 。 可对其已完成的事件使用单个委托或者可对其运行 co_await。 如果同时采用这两种方法则第二种方法会失败。 以下两种完成处理程序都是适当的但不能同时对同一个异步对象使用两者。 auto async_op_with_progress{ CalcPiTo5DPs() }; async_op_with_progress.Completed([](auto const sender, AsyncStatus /* status */) {double pi{ sender.GetResults() }; });auto async_op_with_progress{ CalcPiTo5DPs() }; double pi{ co_await async_op_with_progress };有关完成处理程序的详细信息请参阅异步操作和运算的委托类型。 发后不理 有时某个任务可与其他工作并发执行你无需等待该任务完成因为没有其他工作依赖于它也无需该任务返回值。 在这种情况下可以激发该任务然后忘记它。 为此可以编写返回类型为 winrt::fire_and_forget而不是某个 Windows 运行时异步操作类型或 concurrency:: task的协同例程。 // main.cpp #include winrt/Windows.Foundation.husing namespace winrt; using namespace std::chrono_literals;winrt::fire_and_forget CompleteInFiveSeconds() {co_await 5s; }int main() {winrt::init_apartment();CompleteInFiveSeconds();// Do other work here. }winrt::fire_and_forget 也可用作事件处理程序的返回类型前提是需在其中执行异步操作。 下面是一个示例另请参阅 C/WinRT 中的强引用和弱引用。 winrt::fire_and_forget MyClass::MyMediaBinder_OnBinding(MediaBinder const, MediaBindingEventArgs args) {auto lifetime{ get_strong() }; // Prevent *this* from prematurely being destructed.auto ensure_completion{ unique_deferral(args.GetDeferral()) }; // Take a deferral, and ensure that we complete it.auto file{ co_await StorageFile::GetFileFromApplicationUriAsync(Uri(Lms-appx:///video_file.mp4)) };args.SetStorageFile(file);// The destructor of unique_deferral completes the deferral here. }第一个参数 (sender) 未命名因为我们从未使用它。 因此可以安全地将它保留为引用。 但请注意args 是按值传递的。 请参阅上面的参数传递部分。 等待内核句柄 C/WinRT 提供一个 winrt::resume_on_signal 函数用于在收到内核事件信号之前暂停。 你有责任确保在 co_await resume_on_signal(h) 返回之前句柄始终有效。 resume_on_signal 本身不能为你执行该操作因为在 resume_on_signal 开始之前你就可能已失去句柄如此示例第一个示例所示。 IAsyncAction Async(HANDLE event) {co_await DoWorkAsync();co_await resume_on_signal(event); // The incoming handle is not valid here. }传入的句柄仅在函数返回之前有效该函数为协同程序在第一个暂停点在此示例中为第一个 co_await返回。 在等待 DoWorkAsync 时控制返回到调用方调用帧超出范围你再也无法知道在协同程序继续时句柄是否会有效。 从技术上来说我们的协同程序在按值接收其参数这符合预期请参阅上面的参数传递。 但在此示例中我们需要更进一步因此我们将遵循该指南的精神而不仅仅是字面涵义。 除了句柄我们还需要传递强引用换句话说所有权。 操作方法如下。 IAsyncAction Async(winrt::handle event) {co_await DoWorkAsync();co_await resume_on_signal(event); // The incoming handle *is* valid here. }通过值传递 winrt::handle 可以提供所有权语义确保内核句柄在协同程序生存期内始终有效。 下面介绍如何调用该协同程序。 namespace {winrt::handle duplicate(winrt::handle const other, DWORD access){winrt::handle result;if (other){winrt::check_bool(::DuplicateHandle(::GetCurrentProcess(),other.get(), ::GetCurrentProcess(), result.put(), access, FALSE, 0));}return result;}winrt::handle make_manual_reset_event(bool initialState false){winrt::handle event{ ::CreateEvent(nullptr, true, initialState, nullptr) };winrt::check_bool(static_castbool(event));return event;} }IAsyncAction SampleCaller() {handle event{ make_manual_reset_event() };auto async{ Async(duplicate(event)) };::SetEvent(event.get());event.close(); // Our handle is closed, but Async still has a valid handle.co_await async; // Will wake up when *event* is signaled. }可以将超时值传递给 resume_on_signal如本例所示。 winrt::handle event ...if (co_await winrt::resume_on_signal(event.get(), std::literals::2s)) {puts(signaled); } else {puts(timed out); }异步超时变得很简单 我们对 C/WinRT 的 C 协同程序的投入很大。 协同程序对编写并发代码的影响是变革性的。 就此部分讨论的示例来说异步的详情并不重要重要的是当场获得的结果。 因此C/WinRT 在实现 IAsyncAction Windows 运行时异步操作接口时会提供一个 get 函数与 std::future 提供的 get 函数类似 。 using namespace winrt::Windows::Foundation; int main() {IAsyncAction async ...async.get();puts(Done!); }当异步对象正在完成其操作时get 函数会实施无限期的阻止。 异步对象的生存期往往很短因此通常情况下这正是你所需要的。 但有时候你还有其他要求在超过一定的时间后你不能再等待。 由于 Windows 运行时提供了构建基块因此始终可以编写那样功能的代码。 不过现在 C/WinRT 提供的 wait_for 函数使之变得容易得多。 它也在 IAsyncAction 上进行了实现。同样它与 std::future 提供的 wait_for 函数类似。 using namespace std::chrono_literals; int main() {IAsyncAction async ...if (async.wait_for(5s) AsyncStatus::Completed){puts(done);} }wait_for 在接口上使用 std::chrono::duration但它有一个受限范围该范围小于 std::chrono::duration 提供的值大约为 49.7 天。 下面这个示例中的 wait_for 会先等待约五秒钟然后检查完成情况。 如果比较后得出的结果良好则表明异步对象已成功完成你的任务完成。 如果你在等待某个结果可以随后调用 GetResults 方法来检索结果。 wait_for 和 get 互斥不能同时调用它们 。 它们分别算作一个等待程序Windows 运行时异步操作仅支持一个等待程序。 int main() {IAsyncOperationint async ...if (async.wait_for(5s) AsyncStatus::Completed){printf(result %d\n, async.GetResults());} }由于异步对象到那时已经完成因此 GetResults 方法会立即返回结果无需进一步的等待。 可以看到wait_for 返回了异步对象的状态。 因此你可以将它用于更精细的控制如下所示。 switch (async.wait_for(5s)) { case AsyncStatus::Completed:printf(result %d\n, async.GetResults());break; case AsyncStatus::Canceled:puts(canceled);break; case AsyncStatus::Error:puts(failed);break; case AsyncStatus::Started:puts(still running);break; }请记住AsyncStatus::Completed 意味着异步对象成功完成你可以调用 GetResults 方法来检索任何结果 。AsyncStatus::Canceled 意味着异步对象已取消。 取消通常是由调用方请求的因此需要处理该状态的情况很罕见。 通常会直接将已取消的异步对象丢弃。 如果需要可调用 GetResults 方法来重新引发取消异常。AsyncStatus::Error 意味着从某些方面来看异步对象已失败。 如果需要可调用 GetResults 方法来重新引发异常。AsyncStatus::Started 意味着异步对象仍在运行。 Windows 运行时异步模式不允许多个等待也不允许多个等待程序。 这意味着不能以循环方式调用 wait_for。 如果等待实际上已超时你可以有多个选择。 你可以放弃该对象也可以先轮询其状态然后再调用 GetResults 来检索任何结果。 不过此时最佳选择是直接丢弃该对象。 另一种模式是只检查已启动让 GetResults 处理其他情况。 if (async.wait_for(5s) AsyncStatus::Started) {puts(timed out); } else {// will throw appropriate exception if in canceled or error stateauto results async.GetResults(); }异步返回数组 以下是 MIDL 3.0 示例它生成错误 MIDL2025: [msg]syntax error [context]: expecting or, near [。 Windows.Foundation.IAsyncOperationInt32[] RetrieveArrayAsync();原因在于将数组用作参数化接口的形参类型实参无效。 因此我们需要一种不太明显的方式来实现通过运行时类方法以异步方式传递回数组的目标。 可以将装箱的数组返回到 PropertyValue 对象。 然后调用代码会取消装箱。 以下是一个代码示例在此示例中可以将 SampleComponent 运行时类添加到 Windows Runtime Component (C/WinRT) 项目然后从例如 Core App (C/WinRT) 项目使用它 。 // SampleComponent.idl namespace MyComponentProject {runtimeclass SampleComponent{Windows.Foundation.IAsyncOperationIInspectable RetrieveCollectionAsync();}; }// SampleComponent.h ... struct SampleComponent : SampleComponentTSampleComponent {...Windows::Foundation::IAsyncOperationWindows::Foundation::IInspectable RetrieveCollectionAsync(){co_return Windows::Foundation::PropertyValue::CreateInt32Array({ 99, 101 }); // Box an array into a PropertyValue.} } ...// SampleCoreApp.cpp ... MyComponentProject::SampleComponent m_sample_component; ... auto boxed_array{ co_await m_sample_component.RetrieveCollectionAsync() }; auto property_value{ boxed_array.aswinrt::Windows::Foundation::IPropertyValue() }; winrt::com_arrayint32_t my_array; property_value.GetInt32Array(my_array); // Unbox back into an array. ...
http://www.zqtcl.cn/news/654159/

相关文章:

  • 网站布局模板北京装修大概多少钱一平方
  • 德阳网站建设ghxhwl风景网站模板
  • 昌邑网站建设拓者设计吧现代效果图
  • 学校网站建设成功案例网站开发需要学习哪些内容
  • 怎么让公司建设网站seo于刷网站点击
  • 网站建设合同严瑾建设网站宣传
  • 哪个网站做餐饮推广最好深圳市信任网站
  • 网站模板 整站源码广州网站vi设计报价
  • 百度速页建站wordpress审核插件
  • 怎么给网站wordpress专业的vi设计公司
  • 百度关键词在线优化寻找郑州网站优化公司
  • 网站建设适合什么单位网络推广员工作内容
  • 漂亮的网站维护页面wordpress加个微信登录
  • 网站设计是什么意思创建地址怎么弄
  • nas上建设网站文章网站哪里建设好
  • 消防网站模板广告设计专业需要学什么
  • 建设银行网站首页wordpress 登录函数
  • 做网站多长时间广州营销网站制作
  • 美团外卖网站开发建设网站如何写文案
  • 专门做画册封面的网站开发工程师网站开发工程师招聘
  • 广州市建设局网站自己做电影网站违法
  • 网站建设首选公司大丰专业做网站
  • 用dw怎么做网站辽宁省住房和城乡建设厅网站首页
  • 如何用微信小程序做网站2个网站做的链接怎么用一个域名
  • 大理网站建设滇icp备凡科网站代码如何修改
  • 做电商网站的公司简介网站制作多久
  • 营销手段有哪些方式合肥网站优化服务网
  • 网站备案和域名备案山东临沂市建筑模板生产厂家
  • 三类安全员证查询系统网站建设优化服务机构
  • 网站关键词排名没有了城固县网站建设