Jak: Użyj harmonogramu grupy kontrolować kolejność wykonywania
W Runtime współbieżności kolejność, w jakiej są zaplanowane zadania jest nie deterministyczny.Jednak można użyć planowania polityki wpływ kolejność uruchamiania zadań.W tym temacie przedstawiono sposób używania harmonogramu grupy wraz z concurrency::SchedulingProtocol zasad harmonogram wpływ kolejność uruchamiania zadań.
Przykład uruchamia zestawu zadań dwa razy każdego z różnych zasad planowania.Obie zasady ograniczyć maksymalną liczbę zasobów przetwarzania do dwóch.Pierwsze uruchomienie zastosowań EnhanceScheduleGroupLocality zasad, co jest ustawieniem domyślnym, a drugie uruchomienie zastosowań EnhanceForwardProgress zasad.W obszarze EnhanceScheduleGroupLocality polityki, harmonogram uruchamia wszystkie zadania w jeden harmonogram grupy aż do każdego zadania kończy lub plonów.W obszarze EnhanceForwardProgress polityki, harmonogram po przenosi do następnej grupy harmonogramu w sposób okrężny tylko jedno zadanie zakończy się lub plonów.
Gdy każda grupa harmonogramu zawiera zadania pokrewne, EnhanceScheduleGroupLocality zasad zazwyczaj wyniki lepszą wydajność, ponieważ miejscowości pamięci podręcznej jest zachowywana między zadaniami.EnhanceForwardProgress Zasad włącza do przodu postęp zadań i jest przydatne, gdy wymagają, planowanie uczciwości grup harmonogramu.
Przykład
W tym przykładzie definiuje work_yield_agent klasy, która wynika z concurrency::agent.work_yield_agent Klasy wykonuje jednostka pracy, plony z bieżącego kontekstu, a następnie wykonuje innej jednostki pracy.Agent używa concurrency::wait funkcji wspólnie plon bieżącego kontekstu, tak aby uruchamiać w innych kontekstach.
W tym przykładzie tworzy cztery work_yield_agent obiektów.Aby zilustrować sposób ustawiania zasad harmonogram wpływ na kolejność uruchamiania agentów, przykład kojarzy pierwszych dwóch czynników z jeden harmonogram grupy i dwóch czynników z inną grupą harmonogramu.W przykładzie użyto concurrency::CurrentScheduler::CreateScheduleGroup metodę tworzenia concurrency::ScheduleGroup obiektów.Przykład uruchamia wszystkie cztery agentów dwa razy, przy każdym z różnych zasad planowania.
// 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();
}
Ten przykład generuje następujące wyniki.
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...
Obie zasady produkcji sama sekwencja zdarzeń.Jednakże zasada używający EnhanceScheduleGroupLocality uruchamia zarówno agenci, które są częścią pierwszej grupy harmonogramu, przed jego uruchomieniem czynników, które są częścią grupy drugiej.Zasady, która korzysta z EnhanceForwardProgress rozpoczyna się jeden agent od pierwszej grupy, a następnie uruchamia pierwszy agent w drugiej grupy.
Kompilowanie kodu
Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie planowania protocol.cpp , a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi programu Visual Studio.
cl.exe /EHsc scheduling-protocol.cpp