2015-11-29 11 views
0

Я написал класс с именем 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(), и я должен быть в состоянии гарантировать, что эти объекты будут существовать до тех пор, пока не завершится восстановление детей из-за соединения потоков (которое было проверено с помощью отладчика).

Кто может найти узкое место здесь?

Я смог только найти способ запустить мой код, решение (но для меня более важно объяснение здесь) по-прежнему отсутствует.

С наилучшими пожеланиями

ответ

0

_worker выйдут из области видимости и разрушается, когда цикл повторяются. Вы можете поместить печать в деструктор, чтобы проверить это.

Что вы делаете во втором (новое ..delete) правильно, возможно, вы можете использовать smart_ptr/make_ptr, чтобы избежать удалений.

Вы также можете сделать множество рабочих, а не для цикла, в этом случае вам придется использовать по умолчанию CTOR, и передать инициализаторы (это, начало) в каком-то другом способе

+0

Простых и ясно! Я искал гору, ища муравья! Счастлив, как идиоты, я могу спать сейчас :) Большое спасибо! – Gianks