boost::threads example and heap corruption message
Asked Answered
P

1

7

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,

  • task [name]
  • info
  • quit

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;  
};
Purlieu answered 29/4, 2012 at 15:21 Comment(0)
O
4

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.

Oops answered 29/4, 2012 at 15:41 Comment(4)
A std::deque would work here rather than std::vector since the deque won't reallocate existing entries.Ketron
I did not realize the std::vector reallocated old entries in that way, I was convinced the problem was with my boost::thread library usage.Purlieu
I replaced the std::vector with std::deque and this seems to solve the unwanted behavior. @bamboon Out of interest, you suggest changing the design of the task/taskmanager model I am using, are you suggesting that there is something wrong with it currently?Purlieu
@Purlieu I am not seeing anything wrong anymore. However I recommend you to check out the new C++11 threading features, they already offer a lot of things which you are using like tasks, futures etc. those can simplify your program quite a lot.Oops

© 2022 - 2024 — McMap. All rights reserved.