我已经有了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
s 完成。
代码如下:
#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
那么在进行所有第一级异步函数调用之前,不会进行嵌套的异步函数调用 - 在等待
std::condition_variable
我增加作业数量时,新线程的创建感觉就像成倍地变慢。对于我的试验,低于 100 个工作存在一些异步,但超过 300 个则完全按顺序创建工作。 - 然后,如果我取消注释方法中的
printf
行Start
,所有嵌套的异步都会像魅力一样工作
所以,
- 我在使用中做错了
std::condition_variable
什么? - 为什么为 100 多个线程创建作业会变慢?(这个问题是可选的,似乎是操作系统的问题,可以用智能线程池概念来解决)
- 这
printf
和这些有什么关系?(我尝试printf
在竞争条件下删除所有调用,我在代码中放置了一个断点但没有帮助。情况std::cout
也是如此)
编辑:我添加了启动策略(由 Jonathan Wakely 建议)以确保创建线程。但这也无济于事。我目前正在创建一个std::thread
并调用thread::join
函数以在第一级异步中等待。