std ::对象的内部封装了boost :: thread的对象

时间:2012-02-23 04:52:34

标签: c++ multithreading boost

如何创建std :: vector对象,每个对象都有一个boost :: thread封装在里面。

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());
}

代码编译正常,但输出只是一些垃圾,而不是预期的“abc”。在调试中,我注意到每次调用.push_back()时都会调用~INSTRUMENT()。

由于当前设计的限制,我尝试不使用boost :: group_thread。只是想知道是否有可能有一个带有线程的对象的std :: vector,或者对类似设计的任何建议都会非常有帮助。

我在SO上找到了类似的帖子。它提到了编译器支持的move-semantics,但没有解释它是什么。 How can I add boost threads to a vector

感谢。

2 个答案:

答案 0 :(得分:4)

此代码存在两个问题。

首先,线程在构造boost::thread对象时立即开始运行,因此您需要确保它所访问的任何数据都是事先初始化的 - 即在成员初始化列表中初始化x之前构建线程。

其次,线程使用this对象的INSTRUMENT指针,因此您的对象绑定到特定地址。 std::vector 复制值:当您调用push_back时,它会将对象复制到向量中,如果必须有新的内存块,则添加其他元素可能会复制其他元素分配给腾出空间。这是你看到的析构函数调用的原因:临时构造,push_back将它复制到向量,然后临时被破坏。

要解决此问题,您需要确保一旦构造​​,您的INSTRUMENT对象就无法移动或复制,因为副本具有错误的语义。通过使您的复制构造函数和赋值运算符为私有和未实现(或者如果您有一个支持此新C ++ 11构造的最新编译器将其标记为已删除)或从boost::noncopyable派生来执行此操作。完成此操作后,您不再需要线程shared_ptr,因为它无法共享,因此您可以直接构建它。

如果INSTRUMENT不可复制,则无法将其直接存储在矢量中,因此请在矢量中使用boost::shared_ptr<INSTRUMENT>之类的内容。这将允许向量自由地复制和重新组织其元素,而不会影响INSTRUMENT对象的地址,并确保它在最后被正确销毁。

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));
}

答案 1 :(得分:1)

编辑:您的代码中存在竞争条件。线程在x初始化之前启动。

您应该将矢量更改为vector<boost::shared_ptr<INSTRUMENT> >,然后从boost::shared_ptr内删除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()));
}