すでにジョブの抽象化レイヤーを作成するためのWorker
クラスとクラスがあります。Handler
ミックスに非同期性を注ぎ込むために使用したかったstd::async
のですが、Visual Studio 2012(アップデート1)から奇妙な動作が発生しました。
私のクラス階層は次のとおりです。
Worker
は、純粋仮想メソッドを使用する抽象クラスInit
ですWork
。BasicWorker : Worker
単にprintf
いくつかの出力に使用しています。GroupWorker : Worker
他の労働者の集合体です。Handler
Worker
いくつかの仕事をするために保持します。
次にstd::async
、ワーカーとハンドラーを作成するいくつかのメソッドを呼び出し、ネストされた呼び出しでハンドラーを呼び出し、ワーカーのstd::async
初期化(ここ)を待ってstd::condition_variable
からハンドラーを停止します。
最後に、すべてのが終了するのを待ちstd::future
ます。
コードは次のとおりです。
#include <stdio.h>
#include <future>
#include <array>
#include <atomic>
#include <vector>
struct Worker
{
virtual ~Worker() { }
virtual void Init() = 0;
virtual void Work() = 0;
};
struct BasicWorker : public Worker
{
virtual ~BasicWorker() { }
virtual void Init()
{
printf("\t\t\t\tInit: %d\n", std::this_thread::get_id());
}
virtual void Work()
{
printf("\t\t\t\tWork: %d\n", std::this_thread::get_id());
}
};
struct GroupWorker : public Worker
{
GroupWorker()
{
workers.push_back(std::make_shared<BasicWorker>());
}
virtual ~GroupWorker() { }
virtual void Init()
{
for(int i = 0; i < workers.size(); ++i)
{
workers[i]->Init();
}
initEvent.notify_all();
}
virtual void Work()
{
for(int i = 0; i < workers.size(); ++i)
{
workers[i]->Work();
}
}
void WaitForInit()
{
//std::unique_lock<std::mutex> initLock(initMutex);
//initEvent.wait(initLock);
}
private:
std::mutex initMutex;
std::condition_variable initEvent;
std::vector<std::shared_ptr<Worker>> workers;
};
struct Handler
{
static const int Stopped = -1;
static const int Ready = 0;
static const int Running = 1;
Handler(const std::shared_ptr<Worker>& worker) :
worker(worker)
{ }
void Start(int count)
{
int readyValue = Ready;
if(working.compare_exchange_strong(readyValue, Running))
{
worker->Init();
for(int i = 0; i < count && working == Running; ++i)
{
worker->Work();
}
}
}
void Stop()
{
working = Stopped;
}
private:
std::atomic<int> working;
std::shared_ptr<Worker> worker;
};
std::future<void> Start(int jobIndex, int runCount)
{
//printf("Start: %d\n", jobIndex);
return std::async(std::launch::async, [=]()
{
printf("Async: %d\n", jobIndex);
auto worker = std::make_shared<GroupWorker>();
auto handler = std::make_shared<Handler>(worker);
auto result = std::async(std::launch:async, [=]()
{
printf("Nested async: %d\n", jobIndex);
handler->Start(runCount);
});
worker->WaitForInit();
handler->Stop();
result.get();
});
}
int main()
{
const int JobCount = 300;
const int RunCount = 5;
std::array<std::future<void>, JobCount> jobs;
for(int i = 0; i < JobCount; ++i)
{
jobs[i] = Start(i, RunCount);
}
for(int i = 0; i < JobCount; ++i)
{
jobs[i].get();
}
}
私の問題は:
- 関数内の行のコメントを解除すると
WaitForInit@GroupWorker
、ネストされた非同期関数呼び出しは、すべての第1レベルの非同期関数呼び出しが行われるまで行われません。 - ジョブの数を増やすのを待っ
std::condition_variable
ている間、新しいスレッドの作成は指数関数的に遅くなるように感じます。100未満のジョブのトライアルでは、非同期が存在しますが、300を超えると、ジョブを作成するのは完全にシーケンシャルです。 - 次に
printf
、メソッドの行のコメントを解除するStart
と、ネストされたすべての非同期が魅力のように機能します
それで、
- 使用法で何が間違っています
std::condition_variable
か? - 何百ものスレッドのように、ジョブの作成が遅くなるのはなぜですか?(この質問はオプションであり、OSの問題のようであり、スマートスレッドプールの概念で修正できます)
- これとは何
printf
の関係がありますか?(競合状態の場合にすべての呼び出しを削除しようとprintf
しましたが、コードにブレークポイントを設定しましたが、ヘルプはありません。これも同じですstd::cout
)
編集:スレッドの作成を保証するための起動ポリシー(Jonathan Wakelyによって提案された)を追加しました。しかし、それも役に立ちませんでした。私は現在、第1レベルの非同期内で待機するための関数std::thread
と呼び出し関数を作成しています。thread::join