並列スレッド (典型的なスレッド プールのような) の両方を許可するだけでなく、シリアル実行順序を連続して実行できる C++ スレッド プールの実装を知っている人はいますか。次のスレッドプールを変更してこれを機能させるために数日を費やしましたが、機能させることができないようです。私は intel TBB で使用されている手法を調べました。また、Microsoft の PPL (その非同期エージェント ライブラリは有望に見えます) の概念を使用する可能性も調べました。どちらも上記を達成するためのタスク指向の手法を持っています。しかし、残念ながら、これらのソリューションはターゲットの PowerPC Linux 組み込みターゲットが機能しません。
編集私は、スレッドグラフを生成するソースを使用してライブのcoliruデモをまとめました-また、理論的にはスレッドが完了するのを待つことができるscheduler_loopの良い例も示しています。このコードは、同時実行タスクをフィードする 2 つのスレッドを持つ UtlThreadPool も示しています。
実行グラフを作成するために使用するデータ構造を以下に示します。PriorityNode データ構造を使用します。この構造は基本的に PriorityNode のリンクされたリストであり、それぞれにPriorityLevelのベクトルが含まれています。同時に実行できるタスクと、後で順次実行されるスレッドを示す次の PriorityNode へのポインター。これらがすべて完了したら、mNextNode メンバーが nullptr でない場合は、これをスレッド プールで実行するようにスケジュールする必要があります (mNextNode が nullptr になるまで同様に実行されます。この PriorityNode のリンクされたリストを介したシーケンスは、私がスレッドを希望する方法です) PriorityNode には通常、次のような出力を生成する挿入演算子があります (これは、1A1 を 1A2 と同時に実行でき、これらのスレッドの両方が完了すると、次の PriorityNode が 1B1、1B2、1B3 を許可し、同時に実行するには 1B4 - プールが使用できるスレッドの数に関係なく。
1A1
1A2
+-1B1
+-1B2
+-1B3
+-1B4
私が持っている最も近いものは、この問題の解決策のようです-これはインテル固有のものであり、私はパワーPCを使用していることに注意してください-インテルTBBです-シリアル実行順序に使用する例を次に示します。
/**
* Branch representing fundamental building block of
* a priority tree containing szPriority entries.<p>
*
* Each priority tree struct contains a vector of concurrent
* priorities that can be scheduled to run in the thread pool -
* note that the thread pool must have no entries associated
* with the current channel running before enqueueing these
* tasks. The application must wait for the thread pool to
* complete these tasks before queuing up the dependent tasks
* described in the mNextNode smart pointer. If mNextNode is
* unassigned (nullptr), then we have reached the end of the
* tree.
*/
struct PriorityNode {
explicit PriorityNode(
const std::vector<PriorityLevel>& rConcurrent,
const std::shared_ptr<PriorityNode>& rNext = std::shared_ptr<PriorityNode>(),
const size_t& rDepth = 0)
: mConcurrent(rConcurrent)
, mNextNode(rNext)
, mDepth(rDepth)
{}
/**
* Stream insert operator<p>
*
* @param os [in,out] output stream
* @param rhs [in] PriorityLevel to send to the output
* stream.
*
* @return a reference to the updated stream
*/
inline friend std::ostream& operator << (
std::ostream& os, const PriorityNode& rhs) {
// indent 2 spaces per depth level
std::string indent = rhs.mDepth > 0 ?
(std::string("+") +
std::string((rhs.mDepth * 2) - 1, '-')) :
std::string();
// print out the concurrent threads that
// can be scheduled with the thread pool
for (const auto& next : rhs.mConcurrent) {
os << indent << next << std::endl;
}
// print the dependent priorities that can only
// be scheduled when the concurrent ones are finished
if (rhs.mNextNode) {
os << *rhs.mNextNode << std::endl;
}
return os;
}
// these are all equivalent thread priorities
// that can be run simultaneously
std::vector<PriorityLevel> mConcurrent;
// these are concurrent threads that must be AFTER all
// mConcurrent tasks have completed (exiting the thread pool)
std::shared_ptr<PriorityNode> mNextNode;
// recursion depth
size_t mDepth;
};