boost::threads example and heap corruption message
I'm quite new to boost::threads, I read the documentation and but i'm having some trouble applying it in practice, perhaps you can help? First of all, I have taken the time to write a self contained code listing that demonstrates 2 types of behavior that I cannot yet understand...
The program allows the user to issue 3 different commands,
The purpose is that task will launch some work on a new thread, but then return back to the command prompt while the work is carried out. The user can give the info command to find out which tasks have completed and which have not.
Im using a dual core Win7 machine and Visual Studio 2008 Express.
Problem 1>
Issuing the command, task p1 p2 p3, starts 3 tasks running. This can be checked by issuing info. After a few seconds the work is complete, however for some reason the completed flag is not always set true on 1 or 2 of the tasks.
Problem 2>
Quiting the program then produces the following message:
Windows has triggered a breakpoint in example.exe. This may be due to a corruption of the heap, which indicates a bug in example.exe or any of the DLLs it has loaded. This may also be due to the user pressing F12 while example.exe has focus. The output window may have more diagnostic information.
Hopefully you can reproduce this behavior and help.
Thanks in advance. 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;
};
There is a problem with your code in the taskManager::startTask
method:
mtasks.push_back( task(name) );
// execute start() on a new thread
threads.create_thread( boost::bind( &task::start, &mtasks.back())
The problem here is that on pushing back a new task, your vector might have to reallocate some space and such invalidate the references to your old vector elements, such the following calls to taskinfo
will reference to the wrong elements. As you delete the old elements your heap will somehow get corrupted.
An easy fix would be to reserve some space for the vector in the constructor of your taskManager
class, however you should probably change the design of your task/taskmanager model instead. Another way would be to use a std::deque
, as that one won't reallocate memory.