Aracılığıyla paylaş


Nasıl yapılır: Yürütme Sırasını Etkilemek için Zamanlama Grupları Kullanma

Eşzamanlılık Çalışma Zamanı'nda görevlerin zamanlandığı sıra belirleyici değildir. Ancak, görevlerin çalışma sırasını etkilemek için zamanlama ilkelerini kullanabilirsiniz. Bu konuda, görevlerin çalışma sırasını etkilemek için zamanlama gruplarının eşzamanlılık::SchedulingProtocol zamanlayıcı ilkesiyle birlikte nasıl kullanılacağı gösterilmektedir.

Örnek, her biri farklı bir zamanlama ilkesine sahip olan bir dizi görevi iki kez çalıştırır. Her iki ilke de en fazla işlem kaynağı sayısını iki ile sınırlar. İlk çalıştırma varsayılan ilkeyi EnhanceScheduleGroupLocality , ikinci çalıştırma ise ilkeyi EnhanceForwardProgress kullanır. İlkenin EnhanceScheduleGroupLocality altında zamanlayıcı, her görev bitene veya sonuçlanana kadar tüm görevleri tek bir zamanlama grubunda çalıştırır. İlkenin EnhanceForwardProgress altında zamanlayıcı, yalnızca bir görev tamamlandıktan veya çıktıktan sonra hepsini bir kez deneme şeklinde bir sonraki zamanlama grubuna geçer.

Her zamanlama grubu ilgili görevler içerdiğinde, EnhanceScheduleGroupLocality ilke genellikle görevler arasında önbellek yerelliği korunduğundan performansın artmasına neden olur. İlke EnhanceForwardProgress , görevlerin ileriye doğru ilerlemesini sağlar ve zamanlama grupları arasında eşitlik zamanlamanız gerektiğinde kullanışlıdır.

Örnek

Bu örnek, concurrency::agent öğesinden türetilen sınıfını tanımlarwork_yield_agent. work_yield_agent sınıfı bir iş birimi gerçekleştirir, geçerli bağlamı verir ve sonra başka bir iş birimi gerçekleştirir. Aracı, diğer bağlamların çalışabilmesi için geçerli bağlamı birlikte vermek için eşzamanlılık::wait işlevini kullanır.

Bu örnek dört work_yield_agent nesne oluşturur. Aracıların çalışma sırasını etkilemek için zamanlayıcı ilkelerinin nasıl ayarlandığını göstermek için örnek, ilk iki aracıyı bir zamanlama grubuyla ve diğer iki aracıyı başka bir zamanlama grubuyla ilişkilendirir. Örnek eşzamanlılık::CurrentScheduler::CreateScheduleGroup yöntemini kullanarak eşzamanlılık::ScheduleGroup nesnelerini oluşturur. Örnek, her seferinde farklı bir zamanlama ilkesiyle dört aracıyı da iki kez çalıştırır.

// scheduling-protocol.cpp
// compile with: /EHsc
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

#pragma optimize( "", off )
// Simulates work by performing a long spin loop.
void spin_loop()
{
   for (int i = 0; i < 500000000; ++i)
   {
   }
}
#pragma optimize( "", on )

// Agent that performs some work and then yields the current context.
class work_yield_agent : public agent
{
public:
   explicit work_yield_agent(
      unsigned int group_number, unsigned int task_number)
      : _group_number(group_number)
      , _task_number(task_number)
   {
   }

   explicit work_yield_agent(Scheduler& scheduler,
      unsigned int group_number, unsigned int task_number)
      : agent(scheduler)
      , _group_number(group_number)
      , _task_number(task_number)
   {
   }

   explicit work_yield_agent(ScheduleGroup& group,
      unsigned int group_number, unsigned int task_number)
      : agent(group)       
      , _group_number(group_number)
      , _task_number(task_number)
   {
   }
   
protected:
   // Performs the work of the agent.   
   void run()
   {
      wstringstream header, ss;

      // Create a string that is prepended to each message.
      header << L"group " << _group_number 
             << L",task " << _task_number << L": ";

      // Perform work.
      ss << header.str() << L"first loop..." << endl;
      wcout << ss.str();
      spin_loop();

      // Cooperatively yield the current context. 
      // The task scheduler will then run all blocked contexts.
      ss = wstringstream();
      ss << header.str() << L"waiting..." << endl;
      wcout << ss.str();
      concurrency::wait(0);

      // Perform more work.
      ss = wstringstream();
      ss << header.str() << L"second loop..." << endl;
      wcout << ss.str();
      spin_loop();

      // Print a final message and then set the agent to the 
      // finished state.
      ss = wstringstream();
      ss << header.str() << L"finished..." << endl;
      wcout << ss.str();

      done();
   }  

private:
   // The group number that the agent belongs to.
   unsigned int _group_number;
   // A task number that is associated with the agent.
   unsigned int _task_number;
};

// Creates and runs several groups of agents. Each group of agents is associated 
// with a different schedule group.
void run_agents()
{
   // The number of schedule groups to create.
   const unsigned int group_count = 2;
   // The number of agent to create per schedule group.
   const unsigned int tasks_per_group = 2;

   // A collection of schedule groups.
   vector<ScheduleGroup*> groups;
   // A collection of agents.
   vector<agent*> agents;

   // Create a series of schedule groups. 
   for (unsigned int group = 0; group < group_count; ++group)
   {
      groups.push_back(CurrentScheduler::CreateScheduleGroup());

      // For each schedule group, create a series of agents.
      for (unsigned int task = 0; task < tasks_per_group; ++task)
      {
         // Add an agent to the collection. Pass the current schedule 
         // group to the work_yield_agent constructor to schedule the agent
         // in this group.
         agents.push_back(new work_yield_agent(*groups.back(), group, task));
      }
   }

   // Start each agent.
   for_each(begin(agents), end(agents), [](agent* a) {
      a->start();
   });

   // Wait for all agents to finsih.
   agent::wait_for_all(agents.size(), &agents[0]);

   // Free the memory that was allocated for each agent.
   for_each(begin(agents), end(agents), [](agent* a) {
      delete a;
   });

   // Release each schedule group.
   for_each(begin(groups), end(groups), [](ScheduleGroup* group) {
      group->Release();
   });
}

int wmain()
{
   // Run the agents two times. Each run uses a scheduler
   // policy that limits the maximum number of processing resources to two.

   // The first run uses the EnhanceScheduleGroupLocality 
   // scheduling protocol. 
   wcout << L"Using EnhanceScheduleGroupLocality..." << endl;
   CurrentScheduler::Create(SchedulerPolicy(3, 
      MinConcurrency, 1,
      MaxConcurrency, 2,
      SchedulingProtocol, EnhanceScheduleGroupLocality));

   run_agents();
   CurrentScheduler::Detach();

   wcout << endl << endl;

   // The second run uses the EnhanceForwardProgress 
   // scheduling protocol. 
   wcout << L"Using EnhanceForwardProgress..." << endl;
   CurrentScheduler::Create(SchedulerPolicy(3, 
      MinConcurrency, 1,
      MaxConcurrency, 2,
      SchedulingProtocol, EnhanceForwardProgress));

   run_agents();
   CurrentScheduler::Detach();
}

Bu örnek aşağıdaki çıkışı oluşturur.

Using EnhanceScheduleGroupLocality...
group 0,
    task 0: first loop...
group 0,
    task 1: first loop...
group 0,
    task 0: waiting...
group 1,
    task 0: first loop...
group 0,
    task 1: waiting...
group 1,
    task 1: first loop...
group 1,
    task 0: waiting...
group 0,
    task 0: second loop...
group 1,
    task 1: waiting...
group 0,
    task 1: second loop...
group 0,
    task 0: finished...
group 1,
    task 0: second loop...
group 0,
    task 1: finished...
group 1,
    task 1: second loop...
group 1,
    task 0: finished...
group 1,
    task 1: finished...

Using EnhanceForwardProgress...
group 0,
    task 0: first loop...
group 1,
    task 0: first loop...
group 0,
    task 0: waiting...
group 0,
    task 1: first loop...
group 1,
    task 0: waiting...
group 1,
    task 1: first loop...
group 0,
    task 1: waiting...
group 0,
    task 0: second loop...
group 1,
    task 1: waiting...
group 1,
    task 0: second loop...
group 0,
    task 0: finished...
group 0,
    task 1: second loop...
group 1,
    task 0: finished...
group 1,
    task 1: second loop...
group 0,
    task 1: finished...
group 1,
    task 1: finished...

Her iki ilke de aynı olay dizisini oluşturur. Ancak, kullanan EnhanceScheduleGroupLocality ilke, ikinci grubun parçası olan aracıları başlatmadan önce ilk zamanlama grubunun parçası olan her iki aracıyı da başlatır. kullanan EnhanceForwardProgress ilke, ilk gruptan bir aracı başlatır ve ardından ikinci gruptaki ilk aracıyı başlatır.

Kod Derleniyor

Örnek kodu kopyalayıp bir Visual Studio projesine yapıştırın veya adlı scheduling-protocol.cpp bir dosyaya yapıştırın ve ardından bir Visual Studio Komut İstemi penceresinde aşağıdaki komutu çalıştırın.

cl.exe /EHsc scheduling-protocol.cpp

Ayrıca bkz.

Zamanlama Grupları
Zaman Uyumsuz Aracılar