Soutenir le développement d'Enkits via des sponsors GitHub ou Patreon

Un planificateur de tâches C et C ++ autorisé avec autorisation pour créer des programmes parallèles. Nécessite le support C ++ 11.
Le principal objectif d'Enkits est d'aider les développeurs à créer des programmes qui gèrent à la fois les données et le parallélisme au niveau des tâches pour utiliser la performance complète des processeurs multicore, tout en étant léger (seulement une petite quantité de code) et facile à utiliser.
Enkits a été développé et est utilisé dans la base de code AVOYD d'Enkisoftware.
Enkits est principalement développé sur les architectures Intel X64 et X86 sur MS Windows, avec une prise en charge bien testée pour Linux et un peu moins fréquemment testé en charge sur Mac OS et ARM Android.
Plusieurs exemples existent dans l'exemple de dossier.
Pour d'autres exemples, voir https://github.com/dougbinks/enkitsexamples
La construction d'Enkits est simple, ajoutez simplement les fichiers dans Enkits / SRC à votre système de construction (_c. Les versions UNIX / Linux nécessiteront probablement la bibliothèque PTHREADS.
Pour C ++
#include "TaskScheduler.h"TaskScheduler.cppPour c
#include "TaskScheduler_c.h"TaskScheduler.cppTaskScheduler_c.cppPour CMake, sur Windows / Mac OS X / Linux avec CMake installé, ouvrez une invite dans le répertoire Enkits et:
mkdir buildcd buildcmake ..make all ou pour Visual Studio Open enkiTS.sln Je recommande d'utiliser Enkits directement à partir de la source dans chaque projet plutôt que de l'installer pour une utilisation à l'échelle du système. Cependant, le script CMake d'Enkits peut également être utilisé pour installer la bibliothèque si la variable ENKITS_INSTALL CMake est définie sur ON (il est par OFF ).
Lors de l'installation, les fichiers d'en-tête sont installés dans un sous-répertoire du chemin d'inclusion, include/enkiTS pour s'assurer qu'ils ne sont pas en conflit avec les fichiers d'en-tête d'autres packages. Lors de la création d'applications, assurez-vous que cela fait partie de la variable INCLUDE_PATH ou assurez-vous que Enkits se trouve dans le chemin d'en-tête dans les fichiers source, par exemple, utilisez #include "enkiTS/TaskScheduler.h" au lieu 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 branche compatible C ++ 98 a été obsolète car je ne connais personne.
Les versions du thread utilisateur ne sont plus entretenues car elles ne sont plus utilisées. Des fonctionnalités similaires peuvent être obtenues avec les externaltaskthreads
Avoyd est un jeu abstrait de 6 degrés de Voxel de Freedom. Enkits a été développé pour une utilisation dans notre moteur interne alimente Avoyd.

Générateur de texture GPU / CPU
Le code d'Aras Pranckevičius pour sa série sur les expériences quotidiennes de traçage Path avec diverses langues.
.
Le livre de Marco Castorina et Gabriel Sassone sur le développement d'un moteur de rendu moderne à partir des premiers principes en utilisant l'API Vulkan. Enkits est utilisé comme bibliothèque de tâches pour distribuer des travaux sur les noyaux.
Copyright (C) 2013-2020 Doug Binks
Ce logiciel est fourni «tel quel», sans aucune garantie expresse ou implicite. En aucun cas, les auteurs ne seront tenus responsables de tout dommage résultant de l'utilisation de ce logiciel.
L'autorisation est accordée à quiconque d'utiliser ce logiciel à quelque fin que ce soit, y compris les applications commerciales, et de la modifier et de la redistribuer librement, sous réserve des restrictions suivantes: