Github 스폰서 또는 Patreon을 통해 Enkits의 개발을 지원합니다

병렬 프로그램을 만들기위한 허용 된 C 및 C ++ 작업 스케줄러. C ++ 11 지원이 필요합니다.
Enkits의 주요 목표는 개발자가 데이터 및 작업 레벨 병렬 처리를 모두 처리하여 멀티 코어 CPU의 전체 성능을 활용하는 동안 (소량의 코드 만) 사용하기 쉬운 프로그램을 만들도록 도와줍니다.
Enkits는 Enkisoftware의 Avoyd 코드베이스를 위해 개발되었으며 사용됩니다.
Enkits는 주로 MS Windows의 X64 및 X86 Intel 아키텍처에서 개발되며 Linux에 대한 잘 테스트 된 지원과 Mac OS 및 ARM Android에 대한 지원이 다소 덜 테스트되는 지원입니다.
예제 폴더에는 몇 가지 예가 있습니다.
추가 예는 https://github.com/dougbinks/enkitsexamples를 참조하십시오
Enkits 빌드는 간단합니다. Enkits/SRC의 파일을 빌드 시스템에 추가하십시오 (_c.* C ++ 인터페이스 만 있으면 파일을 무시할 수 있음). UNIX / Linux 빌드에는 PTHREADS 라이브러리가 필요할 것입니다.
C ++의 경우
#include "TaskScheduler.h" 사용하십시오.TaskScheduler.cppc
#include "TaskScheduler_c.h" 사용하십시오.TaskScheduler.cppTaskScheduler_c.cppCMAKE의 경우 CMAKE가 설치된 Windows / Mac OS X / Linux에서 Enkits 디렉토리에서 프롬프트를 열고 다음과 같습니다.
mkdir buildcd buildcmake ..make all 실행하거나 Visual Studio Open enkiTS.sln 위해 시스템 광범위한 사용을 위해 설치하지 않고 각 프로젝트의 소스에서 직접 Enkits를 사용하는 것이 좋습니다. 그러나 ENKITS_INSTALL Cmake 변수가 ON 으로 설정된 경우 ENKITS의 CMAKE 스크립트를 사용하여 라이브러리를 설치할 수도 있습니다 (기본값으로 OFF ).
설치되면 헤더 파일이 포함 된 경로의 하위 디렉토리에 설치되어 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 호환 브랜치는 내가 필요로하는 사람을 모르기 때문에 더 이상 사용되지 않았습니다.
사용자 스레드 버전은 더 이상 사용되지 않기 때문에 더 이상 유지 관리되지 않습니다. 외부 태스크 스레드를 사용하여 유사한 기능을 얻을 수 있습니다
Avoyd는 추상 6 도의 자유 복셀 게임입니다. Enkits는 사내 엔진에 사용하기 위해 개발되었습니다. Avoyd.

GPU/CPU 텍스처 생성기
Aras Pranckevičius의 다양한 언어로 일일 경로 추적기 실험에 대한 그의 시리즈에 대한 코드.
.
Marco Castorina와 Gabriel Sassone의 Bulkan API를 사용한 첫 번째 원칙에서 현대 렌더링 엔진 개발에 관한 책. Enkits는 코어에 작업을 배포하기위한 작업 라이브러리로 사용됩니다.
저작권 (C) 2013-2020 Doug Binks
이 소프트웨어는 명시 적 또는 묵시적 보증없이 'AS-IS'가 제공됩니다. 어떠한 경우에도 저자는이 소프트웨어 사용으로 인한 손해에 대해 책임을지지 않습니다.
상업용 응용 프로그램을 포함하여 모든 목적 으로이 소프트웨어를 사용하고 다음과 같은 제한 사항에 따라이 소프트웨어를 사용 하여이 소프트웨어를 사용하도록 권한이 부여됩니다.