C++异常是否足以实现线程本地存储?

Pot*_*ter 26 c++ exception thread-local

我正在评论一个线程本地存储很好的答案,并回忆起关于异常的另一个信息性讨论

throw块中执行环境的唯一特殊之处在于rethrow引用了异常对象.

将两个和两个放在一起,不会在其主函数的函数catch块中执行整个线程,并将其与线程本地存储一起使用?

虽然很慢,但似乎工作正常.这是小说还是很有特色?还有另一种解决问题的方法吗?我最初的前提是否正确?get_thread您的平台会产生什么样的开销?优化的潜力是什么?

#include <iostream>
#include <pthread.h>
using namespace std;

struct thlocal {
    string name;
    thlocal( string const &n ) : name(n) {}
};

struct thread_exception_base {
    thlocal &th;
    thread_exception_base( thlocal &in_th ) : th( in_th ) {}
    thread_exception_base( thread_exception_base const &in ) : th( in.th ) {}
};

thlocal &get_thread() throw() {
    try {
        throw;
    } catch( thread_exception_base &local ) {
        return local.th;
    }
}

void print_thread() {
    cerr << get_thread().name << endl;
}

void *kid( void *local_v ) try {
    thlocal &local = * static_cast< thlocal * >( local_v );
    throw thread_exception_base( local );
} catch( thread_exception_base & ) {
    print_thread();

    return NULL;
}

int main() {
    thlocal local( "main" );
    try {
        throw thread_exception_base( local );
    } catch( thread_exception_base & ) {
        print_thread();

        pthread_t th;
        thlocal kid_local( "kid" );
        pthread_create( &th, NULL, &kid, &kid_local );
        pthread_join( th, NULL );

        print_thread();
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这确实需要定义派生的新异常类thread_exception_base,初始化基础get_thread(),但总的来说这并不像一个无效的失眠缠身的星期天早晨......

编辑:看起来像GCC使得3个调用pthread_getspecificget_thread.编辑:和堆栈,环境和可执行格式的很多讨厌的内省,找到catch我在第一次演练中错过的块.这看起来高度依赖于平台,因为GCC正在libunwind从操作系统中调用一些.开销大约4000次循环.我想它也必须遍历类层次结构,但可以控制它.

Dan*_*ker 9

在这个问题的俏皮精神中,我提供了这个可怕的噩梦创作:

class tls
{
    void push(void *ptr)
    {
        // allocate a string to store the hex ptr 
        // and the hex of its own address
        char *str = new char[100];
        sprintf(str, " |%x|%x", ptr, str);
        strtok(str, "|");
    }

    template <class Ptr>
    Ptr *next()
    {
        // retrieve the next pointer token
        return reinterpret_cast<Ptr *>(strtoul(strtok(0, "|"), 0, 16));
    }

    void *pop()
    {
        // retrieve (and forget) a previously stored pointer
        void *ptr = next<void>();
        delete[] next<char>();
        return ptr;
    }

    // private constructor/destructor
    tls() { push(0); }
    ~tls() { pop(); }

public:
    static tls &singleton()
    {
        static tls i;
        return i;
    }

    void *set(void *ptr)
    {
        void *old = pop();
        push(ptr);
        return old;
    }

    void *get()
    {
        // forget and restore on each access
        void *ptr = pop();
        push(ptr);
        return ptr;
    }
};
Run Code Online (Sandbox Code Playgroud)

利用根据C++标准的事实,将strtok其第一个参数存储起来以便后续调用可以传递0以从同一个字符串中检索更多的令牌,因此在线程感知实现中它必须使用TLS.

example *e = new example;

tls::singleton().set(e);

example *e2 = reinterpret_cast<example *>(tls::singleton().get());
Run Code Online (Sandbox Code Playgroud)

因此,只要strtok程序中的任何其他地方没有以预期的方式使用,我们就有另一个备用TLS插槽.

  • 这个代码困扰着困扰Paranormal Activity中人们的恶魔. (3认同)