Apoye el desarrollo de Enkits a través de patrocinadores de Github o Patreon

Un programador de tareas C y C ++ con licencia permisiva para crear programas paralelos. Requiere soporte C ++ 11.
El objetivo principal de ENKIT es ayudar a los desarrolladores a crear programas que manejen tanto el paralelismo de los datos y el nivel de tareas para utilizar el rendimiento completo de las CPU multinúcleo, al tiempo que son livianos (solo una pequeña cantidad de código) y fácil de usar.
Enkits fue desarrollado y se usa en la base de código Avoyd de Enkisoftware.
EnKITS se desarrolla principalmente en arquitecturas Intel X64 y X86 en MS Windows, con soporte bien probado para Linux y un soporte con menos frecuencia probado en Mac OS y ARM Android.
Existen varios ejemplos en la carpeta de ejemplo.
Para más ejemplos, consulte https://github.com/dougbinks/enkitsexamples
Construir Enkits es simple, solo agregue los archivos en Enkits/SRC a su sistema de compilación (_c.* Los archivos se pueden ignorar si solo necesita interfaz C ++) y agregue Enkits/SRC a su ruta de inclusión. Las compilaciones de UNIX / Linux probablemente requerirán la biblioteca PTHREADS.
Para c ++
#include "TaskScheduler.h"TaskScheduler.cppPara C
#include "TaskScheduler_c.h"TaskScheduler.cppTaskScheduler_c.cppPara CMake, en Windows / Mac OS X / Linux con CMake instalado, abra una solicitud en el directorio Enkits y:
mkdir buildcd buildcmake ..make all o para visual studio abierto enkiTS.sln Recomiendo usar Enkits directamente desde la fuente en cada proyecto en lugar de instalarlo para uso del sistema. Sin embargo, el script CMake de EnKITS también se puede usar para instalar la biblioteca si la variable CMAKE ENKITS_INSTALL se establece en ON (el valor predeterminado se OFF ).
Cuando se instalan, los archivos de encabezado se instalan en un subdirectorio de la ruta de inclusión, include/enkiTS para garantizar que no entren en conflicto con los archivos de encabezado de otros paquetes. Al construir aplicaciones, asegúrese de que esto sea parte de la variable INCLUDE_PATH o asegúrese de que Enkits esté en la ruta del encabezado en los archivos de origen, por ejemplo, use #include "enkiTS/TaskScheduler.h" en lugar 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 ;
}La rama compatible C ++ 98 se ha desactivado ya que no soy consciente de que nadie la necesite.
Las versiones del hilo del usuario ya no se mantienen ya que ya no están en uso. Se puede obtener una funcionalidad similar con los reales externalTaskThreads
Avoyd es un juego abstracto de 6 grados de libertad Voxel. Enkits fue desarrollado para su uso en nuestro motor interno que enciende a la avoyd.

Generador de textura de GPU/CPU
El código de Aras Pranckevičius para su serie sobre experimentos de trazadores de ruta diaria con varios idiomas.
.
El libro de Marco Castorina y Gabriel Sassone sobre el desarrollo de un motor de renderizado moderno a partir de los primeros principios utilizando la API Vulkan. Enkits se usa como la biblioteca de tareas para distribuir el trabajo en los núcleos.
Copyright (c) 2013-2020 Doug Binks
Este software se proporciona 'as-es', sin ninguna garantía expresa o implícita. En ningún caso los autores serán responsables de los daños derivados del uso de este software.
Se otorga permiso a cualquier persona para usar este software para cualquier propósito, incluidas las aplicaciones comerciales, y para alterarlo y redistribuirlo libremente, sujeto a las siguientes restricciones: