我可以使用static
惯用语thread_local
吗? (假设我将所有class ThisThread{
JNIEnv* jni_env{nullptr};
public:
JNIEnv* getEnv(){
if (!jni_env){
// Attach thread
java_vm->GetEnv((void**)&jni_env, JNI_VERSION);
java_vm->AttachCurrentThread(&jni_env, NULL);
}
return jni_env;
}
~ThisThread(){
if (!jni_env) return;
// Deattach thread
java_vm->DetachCurrentThread();
}
};
static thread_local ThisThread this_thread;
替换为this_thread->getEnv()
)
我需要这个(java jni线程的帮助器):
{{1}}
首先构造,并在每个线程中最后被破坏。 我可以从其他静态或thread_local对象的析构函数/构造函数中调用{{1}}。
更新
Schwarz counter (aka Nifty counter) - 这里,标准说thread_local析构函数称为BEFORE静态,我需要这个后面的。
答案 0 :(得分:1)
我认为最好的解决方案是正常实施schwartz计数器,但是根据ThisThread
静态thread_local
实现Impl
类。
输出的完整示例:
// header file
#include <memory>
#include <mutex>
#include <iostream>
#include <thread>
std::mutex emit_mutex;
template<class...Ts>
void emit(Ts&&...ts)
{
auto action = [](auto&&x) { std::cout << x; };
auto lock = std::unique_lock<std::mutex>(emit_mutex);
using expand = int[];
expand{ 0,
(action(std::forward<Ts>(ts)), 0)...
};
}
struct ThisThread
{
struct Impl
{
Impl()
{
emit("ThisThread created on thread ", std::this_thread::get_id(), '\n');
}
~Impl()
{
emit("ThisThread destroyed on thread ", std::this_thread::get_id(), '\n');
}
void foo()
{
emit("foo on thread ", std::this_thread::get_id(), '\n');
}
};
decltype(auto) foo() { return get_impl().foo(); }
private:
static Impl& get_impl() { return impl_; }
static thread_local Impl impl_;
};
struct ThisThreadInit
{
ThisThreadInit();
~ThisThreadInit();
static int initialised;
};
extern ThisThread& thisThread;
static ThisThreadInit thisThreadInit;
// cppfile
static std::aligned_storage_t<sizeof(ThisThread), alignof(ThisThread)> storage;
ThisThread& thisThread = *reinterpret_cast<ThisThread*>(std::addressof(storage));
int ThisThreadInit::initialised;
thread_local ThisThread::Impl ThisThread::impl_;
ThisThreadInit::ThisThreadInit()
{
if (0 == initialised++)
{
new (std::addressof(storage)) ThisThread ();
}
}
ThisThreadInit::~ThisThreadInit()
{
if (0 == --initialised)
{
thisThread.~ThisThread();
}
}
// now use the object
#include <thread>
int main()
{
thisThread.foo();
auto t = std::thread([]{ thisThread.foo(); });
t.join();
}
示例输出:
ThisThread created on thread 140475785611072
foo on thread 140475785611072
ThisThread created on thread 140475768067840
foo on thread 140475768067840
ThisThread destroyed on thread 140475768067840
ThisThread destroyed on thread 140475785611072
答案 1 :(得分:0)
这不能回答如何使thread_local static
的Schwarz计数器(所以我不接受这个作为答案)。但最后,我提出了这种依赖于平台的(Linux / Android)解决方案。
#include <jni.h>
#include <cassert>
#include "JavaVM.h"
namespace jni_interface{
class ThisThread{
inline static thread_local pthread_key_t p_key;
static void pthread_dstr(void *arg){
if (!jni_env) return;
java_vm->DetachCurrentThread();
jni_env = nullptr;
pthread_setspecific(p_key, NULL);
pthread_key_delete(p_key);
}
static void register_dstr(void *arg){
{
const int res = pthread_key_create(&p_key, pthread_dstr);
assert(res != EAGAIN);
assert(res != ENOMEM);
assert(res == 0);
}
{
const int res = pthread_setspecific(p_key, arg);
assert(res == 0);
}
}
inline static thread_local JNIEnv* jni_env{nullptr};
public:
JNIEnv* getEnv(){
if (!jni_env){
assert(java_vm);
java_vm->GetEnv((void**)&jni_env, JNI_VERSION);
java_vm->AttachCurrentThread(&jni_env, NULL); // safe to call in main thread
register_dstr(jni_env);
}
return jni_env;
}
};
static thread_local ThisThread this_thread;
}
即使出于某种原因,在{C ++'的静态thread_locals(或交错)[换句话说pthread_dstr
在上次使用之前被销毁]之前将调用ThisThread
,在下次调用时对象(getEnv()
)我们重新初始化/重新创建它并注册pthread_dstr
进行另一轮。
NB 总计最大值我们可以有PTHREAD_DESTRUCTOR_ITERATIONS
轮,但是我们总是会在第二轮结束,在最坏的情况下(如果C ++ thread_local实现将使用p_thread析构函数[这意味着我们pthread_dstr
可能不会在第一轮中被称为最后一次]。