带有thread_local的C ++ Schwarz计数器 [英] c++ Schwarz counter with thread_local
问题描述
我可以使用 Schwarz计数器(又名Nifty计数器)惯用语,用thread_local
? (假设我将所有static
替换为thread_local
)
我需要这个(java jni线程的助手):
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;
在每个线程中首先被构造,最后被破坏.
我可以从其他静态或thread_local对象的析构函数/构造函数中调用this_thread->getEnv()
.
更新
https://stackoverflow.com/a/30200992 -在这里,标准表示thread_local析构函数称为BEFORE static,而我需要这个.
我认为最好的解决方案是像往常一样实现schwartz计数器,但要以thread_local
静态Impl
的方式实现ThisThread
类.
带有输出的完整示例:
// 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
Can I use Schwarz counter (aka Nifty counter) idiom, with thread_local
? (Assuming I replace all static
with thread_local
)
I need this (helper for java jni threads):
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;
To be constructed first, and destructed last in each thread.
I may call this_thread->getEnv()
from destructor/constructor of other static or thread_local object.
UPDATE
https://stackoverflow.com/a/30200992 - here, standard says that thread_local destructors called BEFORE static, and I need this one to be after.
I think the best solution is to implement the schwartz counter as normal, but implement the ThisThread
class in terms of a thread_local
static Impl
.
Complete example with outputs:
// 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();
}
example output:
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
这篇关于带有thread_local的C ++ Schwarz计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!