Я написал класс с именем Task, который инкапсулирует поток boost :: thread и позволяет переопределить метод run() для выполнения некоторого задания во вновь созданном потоке.Boost Thread start failure, если объект потока объявлен как член
Вот базовый класс:
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 подзадач (рабочий, также подкласс Задача). Здесь новый метод пробега восстановление:
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();
}
Этот код не удается, так как начало дочернего потока создать sigfault при попытке запустить метод класса Worker бежать, так как он сообщил, как чисто виртуальные и к тому же попытке заблокировать мьютекс на базовый класс 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);
}
Я предпочел бы, чтобы создать Рабочие без нового оператора, так как я на самом деле не нужно держать эти объекты, оставшиеся после завершения функции Restore :: run(), и я должен быть в состоянии гарантировать, что эти объекты будут существовать до тех пор, пока не завершится восстановление детей из-за соединения потоков (которое было проверено с помощью отладчика).
Кто может найти узкое место здесь?
Я смог только найти способ запустить мой код, решение (но для меня более важно объяснение здесь) по-прежнему отсутствует.
С наилучшими пожеланиями
Простых и ясно! Я искал гору, ища муравья! Счастлив, как идиоты, я могу спать сейчас :) Большое спасибо! – Gianks