GithubスポンサーまたはPatreonを介したEnkitの開発をサポートします

並列プログラムを作成するためのC ++タスクスケジューラとC ++タスクスケジューラを許容するC ++タスクスケジューラ。 C ++ 11のサポートが必要です。
エンキットの主な目標は、開発者がデータとタスクレベルの並列性の両方を処理するプログラムを作成して、マルチコアCPUの完全なパフォーマンスを活用するのを支援することですが、軽量(コードの少量のみ)で使いやすいことです。
Enkitsは、EnkisoftwareのAvoyd Codebaseのために開発され、使用されています。
Enkitsは主にMS WindowsのX64およびX86 Intelアーキテクチャで開発されており、Linuxのサポートが十分にテストされており、Mac OSおよびARM Androidでのサポートがやや頻繁にテストされています。
サンプルフォルダーにはいくつかの例があります。
その他の例については、https://github.com/dougbinks/enkitsexamplesを参照してください
ビルディングエンキットはシンプルで、エンキット/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を実行するかシステム全体で使用するためにインストールするのではなく、各プロジェクトのソースからEnkitを直接使用することをお勧めします。ただし、ENKITSのCMAKEスクリプトを使用して、 ENKITS_INSTALL CMAKE変数がONに設定されている場合にライブラリをインストールすることもできます(デフォルトでOFFになります)。
インストールされると、ヘッダーファイルはインクルードパスのサブディレクトリにインストールされます。 include/enkiTS 、他のパッケージのヘッダーファイルと競合しないようにします。アプリケーションを構築する場合#include "enkiTS/TaskScheduler.h"これがINCLUDE_PATH変数#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度の自由度ボクセルゲームです。エンキットは、Avoydを動力とする社内エンジンで使用するために開発されました。

GPU/CPUテクスチャジェネレーター
Daily Path Tracerのさまざまな言語での実験に関する彼のシリーズのArasPranckevičiusのコード。
。
Marco CastorinaとGabriel SassoneのBulkan APIを使用した最初の原則から最新のレンダリングエンジンの開発に関する本。エンキットは、コア全体に作業を配布するためのタスクライブラリとして使用されます。
Copyright(c)2013-2020 Doug Binks
このソフトウェアには、明示的または黙示的な保証なしで「AS-IS」が提供されます。いかなる場合でも、著者はこのソフトウェアの使用から生じる損害について責任を負いません。
商用アプリケーションを含むあらゆる目的のためにこのソフトウェアを使用し、それを変更して自由に再配布する許可が許可されます。