我有一個應用程序使用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;
}
添加了可以清楚顯示問題的Android項目:https://github.com/dantwinkler/android-threading-jni。 – danw
將它縮小了一點,只是提升線程加入。工作示例位於:https://github.com/dantwinkler/android-threading-jni/tree/boost-thread – danw
您是否嘗試啓用完整的CheckJNI? https://developer.android.com/training/articles/perf-jni.html#extended_checking – Delyan