7

Soy bastante nuevo para impulsar :: threads, he leído la documentación y pero estoy teniendo problemas para aplicarla en la práctica, ¿quizás puede ayudarme? En primer lugar, me he tomado el tiempo para escribir un listado de código independiente que demuestra 2 tipos de comportamiento que todavía no puedo entender ...Ejemplo de boost :: threads y mensaje de corrupción de montón

El programa permite al usuario emitir 3 comandos diferentes,

  • tarea [nombre]
  • información
  • dejar

El propósito es que tarea pondrá en marcha un trabajo sobre un nuevo hilo, pero luego regresa al prompt de comando mientras se lleva a cabo el trabajo. El usuario puede dar el comando info para averiguar qué tareas se han completado y cuáles no.

Im utilizando una máquina Win7 dual core y Visual Studio 2008 Express.

Problema 1>

emisión del mandato, tarea S1 S2 S3, comienza 3 tareas en ejecución. Esto se puede verificar emitiendo info. Después de unos segundos, el trabajo está completo; sin embargo, por algún motivo, el indicador completo no siempre se establece como verdadero en 1 o 2 de las tareas.

Problema 2>

Quiting el programa produce entonces el siguiente mensaje:

Windows ha desencadenado un punto de interrupción en ejemplo.exe. Esto puede deberse a una corrupción del montón, que indica un error en example.exe o cualquiera de las DLL que ha cargado. Esto también puede deberse a que el usuario presiona F12 mientras que example.exe tiene foco. La ventana de salida puede tener más información de diagnóstico.

Esperamos poder reproducir este comportamiento y ayudar.

Gracias de antemano. Alex.

//WARNING: THIS CODE DOES NOT BEHAVE EXACTLY AS INTENDED 
#include <iostream> 
#include <string> 
#include <sstream> 
#include <boost/thread.hpp> 

using namespace std; 

class task { 
public: 
    string mname; 
    bool completed; 
    void start() 
    { 
     int a = 0; 
     for (int i=0 ; i<10000; i++) 
     { 
      for (int j=0 ; j<100000; j++) 
      { 
       a= i*2; 
      } 
     } 
     this->completed = true; 
    } 
    task(string name) 
    { 
     mname = name; 
     completed = false; 
    } 
}; 

class taskManager{ 
    public: 
     boost::thread_group threads; 
     void startTask(string name) 
     { 
      //add new task to vector list   
      mtasks.push_back(task(name)); 
      // execute start() on a new thread 
      threads.create_thread(boost::bind(&task::start, &mtasks.back())); 
     } 
     int tasksTotal() 
     { 
      return mtasks.size(); 
     } 
     string taskInfo(int i) 
     { 
      string compstr("Not Completed"); 
      if (mtasks[i].completed == true) 
      { 
       compstr = "Completed"; 
      } 
      return mtasks[i].mname + " " + compstr; 
     } 
    private: 
     vector<task> mtasks; 
}; 

int main(int argc, char* argv[]) 
{ 
    string cmd, temp; 
    stringstream os; 
    bool quit = false; 
    taskManager mm; 

    cout << "PROMPT>"; 

    while (quit == false) 
    { 
     //Wait for a valid command from user 
     getline(cin,cmd); 

     // Reset stringstream and assign new cmd string 
     os.clear(); 
     os << ""; 
     os << cmd; 
     //parse input string 
     while (os >> temp) 
     {    
      if (temp.compare("task") == 0) 
      { 
       while (os >> temp) { mm.startTask(temp); }      
      } 
      if (temp.compare("info") == 0) 
      { 
       // Returns a list of all completed and not completed tasks 
       for (int i = 0; i<mm.tasksTotal(); i++) 
       { 
        cout << mm.taskInfo(i).c_str() << endl; 
       }       
      } 
      if (temp.compare("quit") == 0){ quit = true; } 
     } 

     cout << "PROMPT>"; 
    } 

    mm.threads.join_all();  

    return 0; 
}; 

Respuesta

4

Hay un problema con el código en el método taskManager::startTask:

mtasks.push_back(task(name)); 
// execute start() on a new thread 
threads.create_thread(boost::bind(&task::start, &mtasks.back()) 

El problema aquí es que en empujar hacia atrás una nueva tarea, su vector podría tener que reasignar algo de espacio y tal invalidar la referencias a sus elementos vectoriales antiguos, por ejemplo, las siguientes llamadas al taskinfo harán referencia a los elementos incorrectos. A medida que elimina los elementos antiguos, su montón se corrompe de alguna manera.

Una solución fácil sería reservar espacio para el vector en el constructor de su clase taskManager; sin embargo, probablemente deba cambiar el diseño de su tarea/modelo de administrador de tareas. Otra forma sería usar un std::deque, ya que ese no reasignará la memoria.

+1

Un 'std :: deque' funcionaría aquí en lugar de' std :: vector' ya que el deque no reasignará las entradas existentes. –

+0

@JamesCuster, sí, buena idea, agregó. – inf

+0

No me di cuenta de que std :: vector reasignó las entradas antiguas de esa manera, estaba convencido de que el problema estaba con mi uso de boost :: thread library. – AlexS

Cuestiones relacionadas