简体   繁体   中英

std::vector of objects with a boost::thread encapsulated insde

How do I create a std::vector of objects, and each object has a boost::thread encapsulated inside.

class INSTRUMENT {
public:
    INSTRUMENT() : m_thread(new boost::thread(&INSTRUMENT::Start, this)) {  
        x = "abc";
    } 
    ~INSTRUMENT() {}
    void Start();
public:
    std::string x;
    boost::shared_ptr<boost::thread> m_thread;
};

void INSTRUMENT::Start() {
    try {
        while (1) {
            boost::this_thread::interruption_point();
            std::cout << "here " << x << std::endl;
        }
    } catch (boost::thread_interrupted &thread_e) {
        std::cout << "exit " << x << std::endl;
    } catch (std::exception &e) {
    }
}

std::vector<INSTRUMENT> m_inst_vector;

for (int i = 0; i < 5; i++) {
    m_inst_vector.push_back(INSTRUMENT());
}

The code compiles fine, but the output is just some garbage, not "abc" as expected. In debug, I notice that ~INSTRUMENT() is called every time when .push_back() is called.

I tried not to use boost::group_thread, because of the limitation on the current design. Just wondering whether it is possible to have a std::vector of objects with a thread inside, or any suggestion to a similar design would be very helpful.

I find a similar thread on SO. It mentioned about move-semantics supported in compiler, but didn't explain what it is. How can I add boost threads to a vector

Thanks.

There are two problems with this code.

Firstly, the thread starts running immediately the boost::thread object is constructed, so you need to ensure that any data it accesses is initialized beforehand --- ie initialize x in the member initialization list prior to constructing the thread.

Secondly, the thread uses the this pointer of the INSTRUMENT object, so your object is tied to a specific address. std::vector copies values around: when you call push_back then it copies the object into the vector, and adding additional elements may copy the others around if a new memory block has to be allocated to make room. This is the cause of the destructor calls you see: the temporary is constructed, push_back copies it to the vector, and then the temporary is destructed.

To fix this, you need to ensure that once constructed your INSTRUMENT objects cannot be moved or copied, as copies have the wrong semantics. Do this by making your copy constructor and assignment operator private and unimplemented (or marking them deleted if you have a recent compiler that supports this new C++11 construct), or deriving from boost::noncopyable . Having done this then you no longer need a shared_ptr for the thread, as it cannot be shared, so you can just construct it directly.

If INSTRUMENT is not copyable, you can't store it directly in a vector, so use something like boost::shared_ptr<INSTRUMENT> in the vector. This will allow the vector to freely copy and reshuffle its elements, without affecting the address of the INSTRUMENT object, and ensuring that it is correctly destroyed at the end.

class INSTRUMENT: boost::noncopyable {
public:
    INSTRUMENT() : x("abc"),m_thread(&INSTRUMENT::Start, this) {  
    } 
    ~INSTRUMENT() {}
    void Start();
public:
    std::string x;
    boost::thread m_thread;
};

void INSTRUMENT::Start() {
    try {
        while (1) {
            boost::this_thread::interruption_point();
            std::cout << "here " << x << std::endl;
        }
    } catch (boost::thread_interrupted &thread_e) {
        std::cout << "exit " << x << std::endl;
    } catch (std::exception &e) {
    }
}

std::vector<boost::shared_ptr<INSTRUMENT> > m_inst_vector;

for (int i = 0; i < 5; i++) {
    m_inst_vector.push_back(boost::shared_ptr<INSTRUMENT>(new INSTRUMENT));
}

EDIT : You have a race condition in your code. The thread starts before x gets initialized.

You should change the vector to vector<boost::shared_ptr<INSTRUMENT> > , and remove the boost::shared_ptr from inside INSTRUMENT .

class INSTRUMENT {
public:
    INSTRUMENT() {  
        x = "abc";
        m_thread = boost::thread(&INSTRUMENT::Start, this) 
    } 
    ~INSTRUMENT() {}
    void Start();
public:
    std::string x;
    boost::thread m_thread;
};

for (int i = 0; i < 5; i++) {
    m_inst_vector.push_back(boost::shared_ptr<INSTRUMENT>(new INSTRUMENT()));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM