我写了一个名为Task的类,它封装了一个boost :: thread,并允许覆盖run()方法在新创建的线程上做一些工作。
这是基类:
class Task {
typedef boost::function<void ()> TaskEventCallback;
typedef boost::unordered_map<string, TaskEventCallback> Callbacks;
typedef boost::unordered_map<string, Callbacks> SessionTaskMap;
typedef boost::unordered_map<TaskListener *, SessionTaskMap> ListenersMap;
public:
Task(NGSAppServer& server);
Task(const Task& orig);
virtual ~Task();
virtual void run() = 0;
bool start();
bool pause();
bool cancel();
virtual bool registerListener(TaskListener *);
virtual bool unregisterListener(TaskListener *);
string getProgress();
string getStatusMessage();
boost::thread * getThread();
protected:
void postEvent(string event);
void startThread();
void setProgress(string progress);
void setStatusMessage(string statusMessage);
vector<TaskListener *> listeners;
bool taskRunning;
bool taskStarted;
bool taskCanceled;
bool taskEnded;
NGSAppServer& server;
boost::thread worker;
boost::recursive_mutex mutex;
ListenersMap listeners_map;
private:
string progress;
string statusMessage;
};
该类能够通过服务器类将事件发布到多个http会话,但这里并不相关。 一切正常,线程开始并成功发布事件,直到工作结束。 这是一个工作片段:
RestoreTask * task = new RestoreTask(application->getServer());
TaskListener * listener = new TmpTL(*task, progressText, this);
task->start();
这是Restore类:
class Restore : public Task {
public:
Restore(NGSAppServer& server);
Restore(const Restore& orig);
virtual ~Restore();
virtual void run();
private:
... stuffs ...
};
现在我试图在N subTasks(Worker,也是Task的子类)中拆分Restore任务的工作。 这里是恢复的新运行方法:
std::vector<Worker *> workers;
for(uint i = 0; i < 2; i++){
//Start tread
Worker _worker(this, server);
_worker.start();
workers.push_back(&_worker);
}
//Join Workers
for(uint i = 0; i < 2; i++){
workers.at(i)->getThread()->join();
}
此代码失败,因为子线程的启动在尝试运行Worker类运行方法时创建sigfault,因为它被报告为纯虚拟,而且尝试锁定Task基类上的互斥锁是没有这个断言:
void boost::recursive_mutex::lock(): Assertion `!pthread_mutex_lock(&m)' failed.
直接创建一个Worker对象并启动它(就像还原一样)不会产生任何问题!
初看起来,似乎Restore run()方法在子线程之前已经结束,删除了Worker实例,然后在运行到基类(纯虚拟)并尝试访问被破坏的互斥锁时进行调用。 (如果我错在这里,请纠正我!)
使用调试器深入研究问题我发现情况并非如此。 问题似乎保留在Worker对象声明中,因为以下更改使代码无任何问题:
std::vector<Worker *> workers;
for(uint i = 0; i < 2; i++){
//Start tread
Worker * _worker = new Worker(this, server);
_worker->start();
workers.push_back(_worker);
}
for(uint i = 0; i < 2; i++){
workers.at(i)->getThread()->join();
delete workers.at(i);
}
我更喜欢在没有新操作符的情况下创建Worker,因为在Restore :: run()完成之后我真的不需要保持这些对象的活着,我应该能够保证这些对象仍然存在由于线程连接(已通过调试器验证),子项完成之前一直存在。
谁能在这里找到瓶颈?
我能够找到一种方法来运行我的代码,解决方案(但对我来说更重要的是这里的解释)仍然缺失。
最好的问候
答案 0 :(得分:0)
当重复循环时,_worker将超出范围并被破坏。 您可以在析构函数中放置一个打印来验证这一点。
你在第二个(新的..delete)做的是正确的, 也许你可以使用smart_ptr / make_ptr来避免删除。
您也可以创建一个Worker数组而不是for循环, 在这种情况下,你必须使用默认的ctor,并以其他方式传递初始化器(this,start)