Pergunta

From the output of this sample project I am seeing three copies of my object created when I'd expect only one. And want only one. How should I fix this?

In my real code ThreadedThing is a significantly larger/heavier class that sits in a threadpool and I'd rather have only as many of them as I really need. But I've written a little demo app (below) that demonstrates the behaviour. I copied the basic code from a boost threading sample so I expected it to work properly, so I fear this is a C++ novice question.

I've written multithreaded code before, but in Delphi rather than C++. For this code valgrind says there's no leaks, which is all very well but there are still three objects created where I would rather have one.

#include <iostream>
#include <boost/thread.hpp>

using namespace std;

class ThreadedThing {
public:
    ThreadedThing() {
        cout << "ThreadedThing created" << endl;
    }
    ThreadedThing(const ThreadedThing &orig) {
        cout << "ThreadedThing copy created" << endl;
    }
    ~ThreadedThing() {
        cout << "ThreadedThing destroyed" << endl;
    }
    void operator()() {
        cout << "ThreadedThing running" << endl;
        sleep(2);
    }
};

int main() {
    std::vector < shared_ptr < boost::thread >> threads;
    cout << "Started" << endl;

    ThreadedThing thing;
    std::shared_ptr<boost::thread> thread(new boost::thread(thing));
    threads.push_back(thread);

    for (std::vector < std::shared_ptr < boost::thread >> ::iterator it = threads.begin(); it != threads.end(); ++it) {
        (*it)->join();
        cout << "joined" << endl;
    }
    cout << "stopped" << endl;
    return 0;
}

/* output
Started
ThreadedThing created
ThreadedThing copy created
ThreadedThing copy created
ThreadedThing destroyed
ThreadedThing running
ThreadedThing destroyed
joined
stopped
ThreadedThing destroyed
*/
Foi útil?

Solução

Simply use std::ref in C++11 or boost::ref when not having access to C++11.

Outras dicas

It is well documented that the constructor of boost::thread, same with std::thread, does not accept references as argument. To overcome this problem, you can write a little shell object that encompasses the reference and keeps it even when copied.

This is how I did it:

/* container to allow passing an object reference to std::thread()
 * without this std::thread() would run on a copy
 */
template<typename T>
struct holder {
    holder(T& payload) : payload(payload) {}
    void operator()() { payload(); }

    T& payload;
};

Then use it like this:

BackgroundTaskQueue queue;

// start worker thread
holder<BackgroundTaskQueue> h(queue);
queuethread = new std::thread(h);
// h is not needed anymore
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top