如何:指定特定的计划程序策略

通过计划程序策略,可控制计划程序在管理任务时使用的策略。 本主题演示如何使用计划程序策略来增加将进度指示器打印到控制台的任务的线程优先级。

如需将自定义计划程序策略与异步代理一起使用的示例,请参阅如何:创建使用特定计划程序策略的代理

示例

以下示例并行执行两个任务。 第一个任务计算第 n 个斐波那契数。 第二个任务将进度指示器打印到控制台。

第一个任务使用递归分解来计算斐波那契数。 也就是说,每个任务均以递归方式创建子任务来计算总体结果。 使用递归分解的任务可能会使用所有可用资源,因而使其他任务无资源可用。 在此示例中,打印进度指示器的任务可能无法及时访问计算资源。

为了向打印进度消息的任务提供对计算资源的公平访问,此示例使用如何:管理计划程序实例中所述的步骤来创建具有自定义策略的计划程序实例。 自定义策略将线程优先级指定为最高优先级类。

此示例使用 concurrency::callconcurrency::timer 类来打印进度指示器。 这些类具有其构造函数的版本,这些构造函数引用了计划它们的 concurrency::Scheduler 对象。 该示例使用默认计划程序来计划计算斐波那契数的任务,使用计划程序实例来计划打印进度指示器的任务。

为了说明使用具有自定义策略的计划程序的好处,此示例执行整个任务两次。 本示例首先使用默认计划程序来计划这两个任务。 然后,该示例使用默认计划程序来计划第一个任务,使用具有自定义策略的计划程序来计划第二个任务。

// scheduler-policy.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;

   // Compute the components in parallel.
   int n1, n2;
   parallel_invoke(
      [n,&n1] { n1 = fibonacci(n-1); },
      [n,&n2] { n2 = fibonacci(n-2); }
   );
  
   return n1 + n2;
}

// Prints a progress indicator while computing the nth Fibonacci number.
void fibonacci_with_progress(Scheduler& progress_scheduler, int n)
{
   // Use a task group to compute the Fibonacci number.
   // The tasks in this group are scheduled by the current scheduler.
   structured_task_group tasks;

   auto task = make_task([n] {
      fibonacci(n);
   });
   tasks.run(task);

   // Create a call object that prints its input to the console.
   // This example uses the provided scheduler to schedule the 
   // task that the call object performs.
   call<wchar_t> c(progress_scheduler, [](wchar_t c) { 
      wcout << c; 
   });

   // Connect the call object to a timer object. The timer object
   // sends a progress message to the call object every 100 ms.
   // This example also uses the provided scheduler to schedule the 
   // task that the timer object performs.
   timer<wchar_t> t(progress_scheduler, 100, L'.', &c, true);
   t.start();

   // Wait for the task that computes the Fibonacci number to finish.
   tasks.wait();

   // Stop the timer.
   t.stop();

   wcout << L"done" << endl;
}

int wmain()
{  
   // Calculate the 38th Fibonacci number.
   const int n = 38;

   // Use the default scheduler to schedule the progress indicator while 
   // the Fibonacci number is calculated in the background.

   wcout << L"Default scheduler:" << endl;
   fibonacci_with_progress(*CurrentScheduler::Get(), n);

   // Now use a scheduler that has a custom policy for the progress indicator.
   // The custom policy specifies the thread priority to the highest 
   // priority class.
   
   SchedulerPolicy policy(1, ContextPriority, THREAD_PRIORITY_HIGHEST);
   Scheduler* scheduler = Scheduler::Create(policy);

   // Register to be notified when the scheduler shuts down.
   HANDLE hShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   scheduler->RegisterShutdownEvent(hShutdownEvent);

   wcout << L"Scheduler that has a custom policy:" << endl;
   fibonacci_with_progress(*scheduler, n);

   // Release the final reference to the scheduler. This causes the scheduler
   // to shut down.
   scheduler->Release();

   // Wait for the scheduler to shut down and destroy itself.
   WaitForSingleObject(hShutdownEvent, INFINITE);

   // Close the event handle.
   CloseHandle(hShutdownEvent);
}

本示例生成以下输出。

Default scheduler:
...........................................................................done
Scheduler that has a custom policy:
...........................................................................done

尽管这两组任务产生相同的结果,但是通过使用自定义策略的版本,打印进度指示器的任务能够以提升的优先级运行,以便它响应更快。

编译代码

复制示例代码,并将它粘贴到 Visual Studio 项目中,或粘贴到名为 scheduler-policy.cpp 的文件中,再在 Visual Studio 命令提示符窗口中运行以下命令。

cl.exe/EHsc scheduler-policy.cpp

另请参阅

计划程序策略
如何:管理计划程序实例
如何:创建使用特定计划程序策略的代理