为什么boost::thread_specific_ptr会在几秒钟后冻结android ndk

为什么boost::thread_specific_ptr会在几秒钟后冻结android ndk,android,android-ndk,java-native-interface,Android,Android Ndk,Java Native Interface,我有一个应用程序使用NDK将共享库与java应用程序一起使用。共享库在下面使用线程,并且在库中管理AttachCurrentThread/DetachCurrentThread非常麻烦,因此我尝试使用boost::thread_specific_ptr创建一个管理JNIEnv*的类。问题是如果我在所有应用程序上都使用boost::thread_specific_ptr,那么几秒钟后应用程序就会挂起。有什么建议吗 更新:我添加了第二种方法,我相信这种方法在引擎盖下非常相似,但有同样的问题。还有gd

我有一个应用程序使用NDK将共享库与java应用程序一起使用。共享库在下面使用线程,并且在库中管理AttachCurrentThread/DetachCurrentThread非常麻烦,因此我尝试使用boost::thread_specific_ptr创建一个管理JNIEnv*的类。问题是如果我在所有应用程序上都使用boost::thread_specific_ptr,那么几秒钟后应用程序就会挂起。有什么建议吗

更新:我添加了第二种方法,我相信这种方法在引擎盖下非常相似,但有同样的问题。还有gdb stacktrace:

boost::detail::thread_data_base::~thread_data_base() at thread.cpp:42 0x72e91b74    
boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, XXX>, boost::_bi::list1<boost::_bi::value<XXX*> > > >::~thread_data() at thread.hpp:91 0x72d69198    
boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, XXX>, boost::_bi::list1<boost::_bi::value<XXX*> > > >::~thread_data() at thread.hpp:91 0x72d691e4    
boost::checked_delete<boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, XXX>, boost::_bi::list1<boost::_bi::value<XXX*> > > > >() at checked_delete.hpp:34 0x72d69230  
boost::detail::sp_counted_impl_p<boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, XXX>, boost::_bi::list1<boost::_bi::value<XXX*> > > > >::dispose() at sp_counted_impl.hpp:78 0x72d72c54 
boost::detail::sp_counted_base::release() at sp_counted_base_spin.hpp:103 0x72c67480    
boost::detail::shared_count::~shared_count() at shared_count.hpp:371 0x72c67550 
~shared_ptr() at shared_ptr.hpp:328 0x72e91a3c  
boost::thread::join_noexcept() at thread.cpp:340 0x72e91a3c 
boost::thread::join() at thread.hpp:751 0x72cda274  
第一次尝试

class ThreadJNIEnv
{

private:

    bool        m_bDetach;

    JNIEnv*     m_pJavaEnv;

public:

    ThreadJNIEnv( ) :
        m_pJavaEnv( NULL )
    {
        LOGI( "Attaching Thread" );

        g_pJavaVM->AttachCurrentThread( &m_pJavaEnv, NULL );

        m_bDetach = true;
    }

    ThreadJNIEnv( JNIEnv* pJavaEnv ) :
        m_pJavaEnv( pJavaEnv )
    {
        LOGI( "Attach (main thread): %p ", m_pJavaEnv );

        m_bDetach = false;
    }

    ~ThreadJNIEnv( )
    {
        if( m_bDetach )
        {
            LOGI( "Detaching Thread" );

            g_pJavaVM->DetachCurrentThread( );
        }
    }

    JNIEnv* GetEnv( ) { return m_pJavaEnv; };
};


// Class which manages JNIEnv per thread
boost::thread_specific_ptr<ThreadJNIEnv> g_oJNIEnv;

// Sample thread local data which also hangs the app
boost::thread_specific_ptr<int> g_oValue;

JNIEnv* GetJNIEnv( )
{
    // Do we already have a JNIEnv?
    ThreadJNIEnv* pJNIEnv = g_oJNIEnv.get( );

    if( pJNIEnv == NULL )
    {
        // Create a new JNIEnv (attach the thread)
        g_oJNIEnv.reset( new ThreadJNIEnv( ) );
    }

    return g_oJNIEnv->GetEnv( );
}

jint JNI_OnLoad( JavaVM* vm, void* reserved )
{
    g_pJavaVM = vm;

    g_pJavaVM->GetEnv( (void **)&g_pJniEnv, JNI_VERSION_1_6 );

    // This is a simple one that also exhibits the problem
    g_oValue.reset( new int[10] );

    // Add the main thread environment
    //g_oJNIEnv.reset( new ThreadJNIEnv( pJavaEnv ) );

    LOGI( "JNI_OnLoad called: vm=%p, env=%p", g_pJavaVM, g_pJniEnv );

    return JNI_VERSION_1_6;
}

根据堆栈跟踪,如果我理解正确的话,包含线程的共享指针的销毁是从join开始的,这看起来很奇怪。在我看来,您的github代码似乎还可以,但如果问题出在boost版本上,请尽量避免使用共享指针,并在那里使用作用域线程或移动构造。

添加了正在工作的Android项目,该项目清楚地显示了问题:。将其缩小一点,仅限于boost线程连接。工作示例位于:您是否尝试启用完全检查JNI?看起来问题出在我使用的boost版本1.53上。我编译了boost 1.49,现在它似乎运行良好。最大的问题是什么改变了一切?!?!我计划在这两个方面做一些区别,但现在它的工作。。。
class ThreadJNIEnv
{

private:

    bool        m_bDetach;

    JNIEnv*     m_pJavaEnv;

public:

    ThreadJNIEnv( ) :
        m_pJavaEnv( NULL )
    {
        LOGI( "Attaching Thread" );

        g_pJavaVM->AttachCurrentThread( &m_pJavaEnv, NULL );

        m_bDetach = true;
    }

    ThreadJNIEnv( JNIEnv* pJavaEnv ) :
        m_pJavaEnv( pJavaEnv )
    {
        LOGI( "Attach (main thread): %p ", m_pJavaEnv );

        m_bDetach = false;
    }

    ~ThreadJNIEnv( )
    {
        if( m_bDetach )
        {
            LOGI( "Detaching Thread" );

            g_pJavaVM->DetachCurrentThread( );
        }
    }

    JNIEnv* GetEnv( ) { return m_pJavaEnv; };
};


// Class which manages JNIEnv per thread
boost::thread_specific_ptr<ThreadJNIEnv> g_oJNIEnv;

// Sample thread local data which also hangs the app
boost::thread_specific_ptr<int> g_oValue;

JNIEnv* GetJNIEnv( )
{
    // Do we already have a JNIEnv?
    ThreadJNIEnv* pJNIEnv = g_oJNIEnv.get( );

    if( pJNIEnv == NULL )
    {
        // Create a new JNIEnv (attach the thread)
        g_oJNIEnv.reset( new ThreadJNIEnv( ) );
    }

    return g_oJNIEnv->GetEnv( );
}

jint JNI_OnLoad( JavaVM* vm, void* reserved )
{
    g_pJavaVM = vm;

    g_pJavaVM->GetEnv( (void **)&g_pJniEnv, JNI_VERSION_1_6 );

    // This is a simple one that also exhibits the problem
    g_oValue.reset( new int[10] );

    // Add the main thread environment
    //g_oJNIEnv.reset( new ThreadJNIEnv( pJavaEnv ) );

    LOGI( "JNI_OnLoad called: vm=%p, env=%p", g_pJavaVM, g_pJniEnv );

    return JNI_VERSION_1_6;
}
void DetachThread( )
{
    LOGI( "Detaching Thread" );

    g_pJavaVM->DetachCurrentThread( );
}

JNIEnv* GetJNIEnv( )
{
    JNIEnv* pJNIEnv = NULL;
    int status = g_pJavaVM->GetEnv( (void **)&pJNIEnv, JNI_VERSION_1_6 );

    switch( status )
    {
        case JNI_EDETACHED:
        {
            LOGI( "Attaching Thread" );

            g_pJavaVM->AttachCurrentThread( &pJNIEnv, NULL );

            boost::this_thread::at_thread_exit( DetachThread );
        }
        break;

        case JNI_OK:
        {
            // Everything is ok
        }
        break;

        case JNI_EVERSION:
        {
            LOGE( "GetEnv: version not supported" );
        }
        break;
    }

    LOGI( "GetJNIEnv: %p", pJNIEnv );

    return pJNIEnv;
}