Apoie o desenvolvimento de Enkits através de patrocinadores do GitHub ou Patreon

Um agendador de tarefas C e C ++ licenciado permissivamente para criar programas paralelos. Requer suporte C ++ 11.
O objetivo principal do ENKITS é ajudar os desenvolvedores a criar programas que lidam com o paralelismo de dados e níveis de tarefas para utilizar o desempenho completo das CPUs multicore, sendo leves (apenas uma pequena quantidade de código) e fácil de usar.
O Enkits foi desenvolvido para e é usado na base de código Avoyd da Enkisoftware.
O ENKITS é desenvolvido principalmente nas arquiteturas Intel X64 e X86 no MS Windows, com suporte bem testado para Linux e suporte um pouco com menos frequência no Mac OS e ARM Android.
Vários exemplos existem na pasta Exemplo.
Para mais exemplos, consulte https://github.com/dougbinks/enkitsexamples
Construir enkits é simples, basta adicionar os arquivos no enkits/src ao seu sistema de compilação (os arquivos _c. As compilações Unix / Linux provavelmente exigirão a biblioteca Pthreads.
Para C ++
#include "TaskScheduler.h"TaskScheduler.cppPara c
#include "TaskScheduler_c.h"TaskScheduler.cppTaskScheduler_c.cppPara CMake, no Windows / Mac OS X / Linux com CMake instalado, abra um prompt no diretório Enkits e:
mkdir buildcd buildcmake ..make all ou para o Visual Studio Open enkiTS.sln Eu recomendo o uso do enkits diretamente da fonte em cada projeto, em vez de instalá -lo para uso amplo do sistema. No entanto, o script cMake da Enkits também pode ser usado para instalar a biblioteca se a variável ENKITS_INSTALL cmake estiver definida como ON (o padrão é OFF ).
Quando instalados, os arquivos do cabeçalho são instalados em um subdiretório do caminho incluir, include/enkiTS para garantir que eles não entrem em conflito com os arquivos de cabeçalho de outros pacotes. Ao criar aplicativos, certifique -se de que isso faça parte da variável INCLUDE_PATH ou verifique se o Enkits está no caminho do cabeçalho nos arquivos de origem, por exemplo, use #include "enkiTS/TaskScheduler.h" em vez de #include "TaskScheduler.h" .
#include "TaskScheduler.h"
enki:: TaskScheduler g_TS ;
// define a task set, can ignore range if we only do one thing
struct ParallelTaskSet : enki :: ITaskSet {
void ExecuteRange ( enki :: TaskSetPartition range_ , uint32_t threadnum_ ) override {
// do something here, can issue tasks with g_TS
}
};
int main ( int argc , const char * argv []) {
g_TS . Initialize ();
ParallelTaskSet task ; // default constructor has a set size of 1
g_TS . AddTaskSetToPipe ( & task );
// wait for task set (running tasks if they exist)
// since we've just added it and it has no range we'll likely run it.
g_TS . WaitforTask ( & task );
return 0 ;
} #include "TaskScheduler.h"
enki:: TaskScheduler g_TS ;
int main ( int argc , const char * argv []) {
g_TS . Initialize ();
enki:: TaskSet task ( 1 , []( enki :: TaskSetPartition range_ , uint32_t threadnum_ ) {
// do something here
} );
g_TS . AddTaskSetToPipe ( & task );
g_TS . WaitforTask ( & task );
return 0 ;
} // See full example in Priorities.cpp
#include "TaskScheduler.h"
enki:: TaskScheduler g_TS ;
struct ExampleTask : enki :: ITaskSet
{
ExampleTask ( ) { m_SetSize = size_ ; }
void ExecuteRange ( enki :: TaskSetPartition range_ , uint32_t threadnum_ ) override {
// See full example in Priorities.cpp
}
};
// This example demonstrates how to run a long running task alongside tasks
// which must complete as early as possible using priorities.
int main ( int argc , const char * argv [])
{
g_TS . Initialize ();
ExampleTask lowPriorityTask ( 10 );
lowPriorityTask . m_Priority = enki :: TASK_PRIORITY_LOW ;
ExampleTask highPriorityTask ( 1 );
highPriorityTask . m_Priority = enki :: TASK_PRIORITY_HIGH ;
g_TS . AddTaskSetToPipe ( & lowPriorityTask );
for ( int task = 0 ; task < 10 ; ++ task )
{
// run high priority tasks
g_TS . AddTaskSetToPipe ( & highPriorityTask );
// wait for task but only run tasks of the same priority or higher on this thread
g_TS . WaitforTask ( & highPriorityTask , highPriorityTask . m_Priority );
}
// wait for low priority task, run any tasks on this thread whilst waiting
g_TS . WaitforTask ( & lowPriorityTask );
return 0 ;
} #include "TaskScheduler.h"
enki:: TaskScheduler g_TS ;
// define a task set, can ignore range if we only do one thing
struct PinnedTask : enki :: IPinnedTask {
void Execute () override {
// do something here, can issue tasks with g_TS
}
};
int main ( int argc , const char * argv []) {
g_TS . Initialize ();
PinnedTask task ; //default constructor sets thread for pinned task to 0 (main thread)
g_TS . AddPinnedTask ( & task );
// RunPinnedTasks must be called on main thread to run any pinned tasks for that thread.
// Tasking threads automatically do this in their task loop.
g_TS . RunPinnedTasks ();
// wait for task set (running tasks if they exist)
// since we've just added it and it has no range we'll likely run it.
g_TS . WaitforTask ( & task );
return 0 ;
} #include "TaskScheduler.h"
enki:: TaskScheduler g_TS ;
// define a task set, can ignore range if we only do one thing
struct TaskA : enki :: ITaskSet {
void ExecuteRange ( enki :: TaskSetPartition range_ , uint32_t threadnum_ ) override {
// do something here, can issue tasks with g_TS
}
};
struct TaskB : enki :: ITaskSet {
enki:: Dependency m_Dependency ;
void ExecuteRange ( enki :: TaskSetPartition range_ , uint32_t threadnum_ ) override {
// do something here, can issue tasks with g_TS
}
};
int main ( int argc , const char * argv []) {
g_TS . Initialize ();
// set dependencies once (can set more than one if needed).
TaskA taskA ;
TaskB taskB ;
taskB . SetDependency ( taskB . m_Dependency , & taskA );
g_TS . AddTaskSetToPipe ( & taskA ); // add first task
g_TS . WaitforTask ( & taskB ); // wait for last
return 0 ;
} #include "TaskScheduler.h"
enki:: TaskScheduler g_TS ;
struct ParallelTaskSet : ITaskSet
{
void ExecuteRange ( enki :: TaskSetPartition range_ , uint32_t threadnum_ ) override {
// Do something
}
};
void threadFunction ()
{
g_TS . RegisterExternalTaskThread ();
// sleep for a while instead of doing something such as file IO
std::this_thread::sleep_for( std ::chrono:: milliseconds ( num_ * 100 ) );
ParallelTaskSet task ;
g_TS . AddTaskSetToPipe ( & task );
g_TS . WaitforTask ( & task );
g_TS . DeRegisterExternalTaskThread ();
}
int main ( int argc , const char * argv [])
{
enki:: TaskSchedulerConfig config ;
config . numExternalTaskThreads = 1 ; // we have one extra external thread
g_TS . Initialize ( config );
std:: thread exampleThread ( threadFunction );
exampleThread . join ();
return 0 ;
}# include " TaskScheduler.h "
enki::TaskScheduler g_TS;
struct RunPinnedTaskLoopTask : enki::IPinnedTask
{
void Execute () override
{
while ( !g_TS. GetIsShutdownRequested () )
{
g_TS. WaitForNewPinnedTasks (); // this thread will 'sleep' until there are new pinned tasks
g_TS. RunPinnedTasks ();
}
}
};
struct PretendDoFileIO : enki::IPinnedTask
{
void Execute () override
{
// Do file IO
}
};
int main ( int argc, const char * argv[])
{
enki::TaskSchedulerConfig config;
// In this example we create more threads than the hardware can run,
// because the IO thread will spend most of it's time idle or blocked
// and therefore not scheduled for CPU time by the OS
config. numTaskThreadsToCreate += 1 ;
g_TS. Initialize ( config );
// in this example we place our IO threads at the end
RunPinnedTaskLoopTask runPinnedTaskLoopTasks;
runPinnedTaskLoopTasks. threadNum = g_TS. GetNumTaskThreads () - 1 ;
g_TS. AddPinnedTask ( &runPinnedTaskLoopTasks );
// Send pretend file IO task to external thread FILE_IO
PretendDoFileIO pretendDoFileIO;
pretendDoFileIO. threadNum = runPinnedTaskLoopTasks. threadNum ;
g_TS. AddPinnedTask ( &pretendDoFileIO );
// ensure runPinnedTaskLoopTasks complete by explicitly calling shutdown
g_TS. WaitforAllAndShutdown ();
return 0 ;
}A filial compatível com C ++ 98 foi presa, pois não estou ciente de alguém que precisa.
As versões do thread do usuário não estão mais sendo mantidas, pois não estão mais em uso. Funcionalidade semelhante pode ser obtida com o Externaltaskthreads
Avoyd é um jogo abstrato de 6 graus de liberdade voxel. O Enkits foi desenvolvido para uso em nosso motor interno, alimentando o Avoyd.

Gerador de textura GPU/CPU
O código de Aras Pranckevičius para sua série em experimentos diários de rastreamento de caminhos com vários idiomas.
.
O livro de Marco Castorina e Gabriel Sassone sobre o desenvolvimento de um mecanismo de renderização moderno a partir dos primeiros princípios usando a API Vulkan. O ENKITS é usado como biblioteca de tarefas para distribuir trabalhos entre núcleos.
Copyright (c) 2013-2020 Doug Binks
Este software é fornecido 'como está', sem qualquer garantia expressa ou implícita. Em nenhum caso os autores serão responsabilizados por quaisquer danos decorrentes do uso deste software.
A permissão é concedida a qualquer pessoa para usar este software para qualquer finalidade, incluindo aplicativos comerciais, e alterá -lo e redistribuí -lo livremente, sujeito às seguintes restrições: