Поддержка разработки энкетов через спонсоров GitHub или Patreon

Планировщик задач с разрешением C и C ++ для создания параллельных программ. Требуется поддержка C ++ 11.
Основная цель энкетов - помочь разработчикам создать программы, которые обрабатывают параллелизм как данных, так и уровня задач, чтобы использовать полную производительность многоядерных процессоров, в то же время является легким (только небольшое количество кода) и простых в использовании.
Enkits был разработан и используется в кодовой базе EnkiSoftware.
Enkits в основном разрабатывается на архитектурах x64 и x86 Intel на MS Windows, с хорошо протестированной поддержкой Linux и несколько реже проверенной поддержкой на Mac OS и Arm Android.
Несколько примеров существуют в примере папки.
Для получения дополнительных примеров см. Https://github.com/dougbinks/enkitsexamples
Создание Enkits просто, просто добавьте файлы в Enkits/SRC в вашу систему сборки (_c.* Файлы можно игнорировать, если вам нужен только интерфейс C ++) и добавить Enkits/src в свой путь включения. Сборки Unix / Linux, вероятно, потребуют библиотеки Pthreads.
Для C ++
#include "TaskScheduler.h"TaskScheduler.cppДля c
#include "TaskScheduler_c.h"TaskScheduler.cppTaskScheduler_c.cppДля Cmake, в Windows / Mac OS X / Linux с установленным Cmake, откройте подсказку в каталоге Enkits и:
mkdir buildcd buildcmake ..make all или для Visual Studio Open enkiTS.sln Я рекомендую использовать Enkits непосредственно из Source в каждом проекте, а не устанавливать его для широкого использования системы. Однако скрипт Cmake 'Cmake также может использоваться для установки библиотеки, если переменная ENKITS_INSTALL cmake установлена на ON (она по умолчанию OFF ).
При установке файлы заголовков устанавливаются в подкаталорике PATH, include/enkiTS чтобы убедиться, что они не конфликтуют с файлами заголовков из других пакетов. При создании приложений либо убедитесь, что это является частью переменной INCLUDE_PATH , либо убедитесь, что enkits находится в пути заголовка в исходных файлах, например, используйте #include "enkiTS/TaskScheduler.h" вместо #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 ;
}Совместимая ветвь C ++ 98 устарела, так как я не знаю, что кто -либо, что ему нужен.
Версии пользовательского потока больше не поддерживаются, поскольку они больше не используются. Подобные функциональности можно получить с помощью ExternalTaskThreads
Avoyd - абстрактная 6 градусов Freedom Voxel Game. Enkits был разработан для использования в нашем собственном двигателе Avoyd.

Грузополовный генератор текстур графического процессора/процессора
Код Арас Пранккевичю для его серии о ежедневных экспериментах по трассеру с различными языками.
Полем
Книга Марко Касторина и Габриэля Сассоне по разработке современного двигателя рендеринга из первых принципов с использованием Vulkan API. Enkits используется в качестве библиотеки задач для распространения работы по ядрам.
Copyright (C) 2013-2020 Doug Binks
Это программное обеспечение предоставляется «как есть», без какой-либо явной или подразумеваемой гарантии. Ни в коем случае авторы не будут нести ответственность за любые убытки, возникающие в результате использования этого программного обеспечения.
Разрешение предоставляется всеми, чтобы использовать это программное обеспечение для любых целей, включая коммерческие приложения, а также изменять его и свободно перераспределить, при условии следующих ограничений: