【问题标题】:(simple) boost thread_group question(简单)提升线程组问题
【发布时间】:2010-11-17 19:45:54
【问题描述】:

我正在尝试编写一个相当简单的线程应用程序,但对 boost 的线程库还是陌生的。我正在做的一个简单的测试程序是:

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

int result = 0;
boost::mutex result_mutex;

boost::thread_group g;

void threaded_function(int i)
{
    for(; i < 100000; ++i) {}

    {
        boost::mutex::scoped_lock lock(result_mutex);
        result += i;
    }
}

int main(int argc, char* argv[])
{
    using namespace std;

    // launch three threads
    boost::thread t1(threaded_function, 10);
    boost::thread t2(threaded_function, 10);
    boost::thread t3(threaded_function, 10);

    g.add_thread(&t1);
    g.add_thread(&t2);
    g.add_thread(&t3);

    // wait for them
    g.join_all();

    cout << result << endl;

    return 0;
}

但是,当我编译并运行这个程序时,我得到了

的输出
$ ./test 
300000
test: pthread_mutex_lock.c:87: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
Aborted

显然,结果是正确的,但我担心这个错误消息,特别是因为具有基本相同结构的实际程序卡在 join_all() 点。有人可以向我解释发生了什么吗?有没有更好的方法来做到这一点,即启动多个线程,将它们存储在外部容器中,然后在继续程序之前等待它们全部完成?

感谢您的帮助。

【问题讨论】:

    标签: c++ multithreading boost boost-thread


    【解决方案1】:

    我认为您的问题是由程序退出时调用的 thread_group 析构函数引起的。线程组想要负责破坏你的线程对象。另请参阅boost::thread_group 文档。

    您正在堆栈上创建线程对象作为主函数范围内的局部变量。因此,当程序退出并且thread_group试图删除它们时,它们已经被破坏了。

    作为一种解决方案,使用 new 在堆上创建线程对象,并让 thread_group 处理它们的销毁:

    boost::thread *t1 = new boost::thread(threaded_function, 10);
    ...
    g.add_thread(t1);
    ...
    

    【讨论】:

    • 您应该删除“新”内存分配并将其交给 thread_group 之间的省略号。否则,如果中间代码出现问题(即抛出),您将泄漏线程。
    • 是的,这似乎是这种情况,也是较大程序中的错误的原因。工作示例现在使用: // 启动三个线程 g.add_thread(new boost::thread(threaded_function, 10)); g.add_thread(new boost::thread(thread_function, 10)); g.add_thread(new boost::thread(thread_function, 10));
    • 确保不泄漏的一个好方法是使用 std::unique_ptr 或类似的解决方案,并使用 ptr.get() 将线程提供给group_thread。
    • 如果添加到组的线程数是无限的,他不应该在线程组终止时也从线程组中删除线程吗?而不是让死线程堆积起来直到程序结束?
    • 这解决了*** glibc detected *** ...: double free or corruption (out)
    【解决方案2】:

    如果您不需要线程句柄,请尝试使用 thread_group::create_thread(),它完全无需管理线程:

    // Snip: Same as previous examples
    
    int main(int argc, char* argv[])
    {
        using namespace std;
    
        // launch three threads
        for ( int i = 0; i < 3; ++i )
            g.create_thread( boost::bind( threaded_function, 10 ) );
    
        // wait for them
        g.join_all();
    
        cout << result << endl;
    
        return 0;
    }
    

    【讨论】:

    • create_thread 仍然返回线程 boost.org/doc/libs/1_39_0/doc/html/thread/… 的句柄。这种情况下之所以可以使用create_thread,是因为与add_thread不同,线程组不负责删除线程。
    • 仅供参考。可以理解,之前的评论是错误的,因为文档没有明确所有权。但是,从查看 1.55.0 的源代码来看,create_threadadd_thread both 将线程添加到内部数组中,该数组被迭代在析构函数中并在退出时删除。该代码通过create_thread将对象存储在堆上,而原始代码将对象存储在堆栈上;因此,当堆栈展开时,对象会被删除一次,然后在应用程序退出时删除组时再次删除。
    【解决方案3】:

    add_thread() 获取您传入的线程的所有权。线程组删除线程。在此示例中,您正在删除分配在堆栈上的内存,这几乎是一种死罪。

    成员函数 add_thread()

    void add_thread(thread* thrd);

    前提条件

    表达式 delete thrd 是 形成良好,不会导致 未定义的行为。

    效果:

    取得 boost::thread 的所有权 thrd 指向的对象并添加它 到组。

    后置条件

    this->size() 加一。

    不确定这是否是您的代码有问题,或者这只是示例错误。否则代码看起来不错。

    【讨论】:

      【解决方案4】:

      看起来以上都没有真正回答这个问题。

      我遇到了类似的问题。此警告的结果 (pthread_mutex_lock.c:87: __pthread_mutex_lock: Assertion `mutex->_data._owner == 0' 失败。 Aborted)是有时程序会泄漏线程并导致 boost_resource_error 异常。

      原因看起来程序在 join_all() 之后继续执行,尽管大多数线程仍在运行(未终止)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-02
        • 2011-04-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多