我编写了一个名为 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();
这是恢复类:
class Restore : public Task {
public:
Restore(NGSAppServer& server);
Restore(const Restore& orig);
virtual ~Restore();
virtual void run();
private:
... stuffs ...
};
现在我尝试将还原任务的工作拆分为 N 个子任务(Worker,也是任务的子类)。这里是恢复的新运行方法:
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 类 run 方法时创建了一个 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);
}
我更喜欢在没有 new 运算符的情况下创建 Workers,因为在 Restore::run() 完成后我真的不需要让这些对象保持活动状态,并且我应该能够保证这些对象仍然存在,直到孩子们完成,因为线程加入(已通过调试器验证)。
谁能找到这里的瓶颈?
我已经能够找到一种方法来运行我的代码,但仍然缺少解决方案(但对我来说更重要的是这里的解释)。
最好的祝福