带有thread_local的C ++ Schwarz计数器 [英] c++ Schwarz counter with thread_local

查看:103
本文介绍了带有thread_local的C ++ Schwarz计数器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆