2013-07-30 76 views
1

我有一個應用程序使用NDK來與Java應用程序一起使用共享庫。共享庫使用下面的線程,並且管理庫中的AttachCurrentThread/DetachCurrentThread非常尷尬,所以我試圖使用boost :: thread_specific_ptr創建一個管理JNIEnv *的類。問題是如果我使用boost :: thread_specific_ptr在所有應用程序幾秒鐘後掛起。有什麼建議麼?!?!爲什麼boost :: thread_specific_ptr在幾秒鐘後凍結了android ndk

更新:我添加了第二種方法,我相信這是非常相似的引擎蓋下,但也有同樣的問題。也有gdb的堆棧跟蹤:

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 

的問題似乎在於在析構函數,其中i - > _ M_current爲空,仍通過提升代碼的工作我的方式,看看有什麼可能是真正的問題,但它是緩慢的運動。

thread_data_base::~thread_data_base() 
    { 
     for (notify_list_t::iterator i = notify.begin(), e = notify.end(); 
       i != e; ++i) 
     { 
      i->second->unlock(); 
      i->first->notify_all(); 
     } 
     for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end(); 
       i != e; ++i) 
     { 
      (*i)->make_ready(); 
     } 
    } 

首先嚐試

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; 
} 
+0

添加了可以清楚顯示問題的Android項目:https://github.com/dantwinkler/android-threading-jni。 – danw

+0

將它縮小了一點,只是提升線程加入。工作示例位於:https://github.com/dantwinkler/android-threading-jni/tree/boost-thread – danw

+0

您是否嘗試啓用完整的CheckJNI? https://developer.android.com/training/articles/perf-jni.html#extended_checking – Delyan

回答

0

根據堆棧跟蹤,如果我正確地理解的,共享指針的破壞,包含螺紋,從開始join,這似乎很奇怪。你的github代碼對我來說確實很好,但如果問題出現在boost版本上,請儘量避免使用共享指針,並在其中使用scoped_thread或移動構造。