• 线程局部存储空间 pthread_key_t、__thread 即 ThreadLocal


    https://www.jianshu.com/p/495ea7ce649b?utm_source=oschina-app

    该博客还未学习完  还有   pthread_key_t    Thread_local

    __thread 修饰的变量

    • __thread是GCC内置的线程局部存储设施,__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是各线程独立不干扰的变量;
    • 只能修饰POD类型(类似整型指针的标量),不能修饰class类型,因为无法自动调用构造函数和析构函数;
    • 可以用于修饰全局变量,函数内的静态变量,不能修饰函数的局部变量或者class的普通成员变量;
    • 且__thread变量值只能初始化为编译器常量。
    #include <pthread.h>
    #include <cstdio>
    #include <cstdlib>
    #include <assert.h>
    #include <stdint.h>
    
    __thread uint64_t pkey = 0;
    
    void run2( )
    {
        FILE* fp = NULL;
        cout<<"thread1 run2  thread = "<<pkey<<endl;//有值了 
        
        if( !pkey )
        {
            char fName[128] = "";
            sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) );
            fp   = fopen( fName, "w" );
            pkey = reinterpret_cast<uint64_t>( fp ); 
    
        }else fp = reinterpret_cast<FILE*>( pkey );
    
        fprintf( fp, "hello __thread 2
    " );
        return ;
    }
    
    void* run1( void* arg )
    {
        FILE* fp = NULL;
        cout<<"thread1 run1  thread = "<<pkey<<endl;// 0
        
        if( !pkey )
        {
            char fName[128] = "";
            sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) );
            fp   = fopen( fName, "w" );
            pkey = reinterpret_cast<uint64_t>( fp ); 
    
        }else fp = reinterpret_cast<FILE*>( pkey );
    
        fprintf( fp, "hello __thread 1
    " );
    
        run2();
    
        return NULL;
    }
    
    int main(int argc, char const *argv[])
    {
        char fName[128] = "";
        sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) );
        FILE* fp = fopen( fName, "w" );
        cout<<"main  thread = "<<pkey<<endl;//0
        
        pkey = reinterpret_cast<uint64_t>( fp );
        fprintf( fp, "hello __thread
    " );
        cout<<"main  thread  end = "<<pkey<<endl;///其他值
    
        pthread_t threads[2];
        pthread_create( &threads[0], NULL, run1, NULL );//开启线程
        pthread_create( &threads[1], NULL, run1, NULL );
        pthread_join( threads[0], NULL );
        pthread_join( threads[1], NULL );
        return 0;
    }
    
    
    main  thread = 0
    main  thread  end = 11430944
    thread1 run1  thread = 0
    thread1 run2  thread = 140098611972288
    thread1 run1  thread = 0
    thread1 run2  thread = 140098611976960
    
    一共创建了 3个文件  分别对应三个线程

    pthread_key_t

    pthread_key_t 优于 __thread 从下面几个方面来说:

    • 依赖 linux 环境的 libpthread, 而非 gcc 编译器可移植性增强
    • 如上所示,可以认为对每个 pthread_key, 库内部提供了一个 __thread void* 接受 pthread_setspecific 设置的指针,从而可以指向 class 类型
    • pthread_key_t 可以作为函数的局部变量,也可以作为局部变量

    #include <pthread.h> 
        // pthread_key_t, pthread_setspecific, pthread_getspecific, pthread_self
        // pthread_key_create, pthread_key_delete, pthread_create, pthread_join
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    
    using namespace std;
     
    static pthread_key_t pkt;
    // 1, callback function to destroy resource associated with key
    // 2, the in_param is pthread_getspecific()
    // 3, gettid()是内核给线程(轻量级进程)分配的进程id,全局(所有进程中)唯一
    // 4, pthread_self()是在用户态实现的,获取的id实际上是主线程分配给子线程的线程描述符的地址而已,只是在当前进程空间中是唯一的。
    void destroy( void *arg )
    {
        printf("exit at thread %d, fclose file 
    ", static_cast<int>( pthread_self() ) );
        if( arg ) fclose( reinterpret_cast<FILE*>(arg) );
    }
    // 5, pthread_getspecific() Return current value of the thread-specific data slot identified by KEY.
    void writeLog( const char* log )
    {
        FILE* logHandle = reinterpret_cast<FILE*>( pthread_getspecific( pkt) );
        fprintf( logHandle, "%s
    ", log );
    }
    // 6, pthread_setspecific Store POINTER in the thread-specific data slot identified by KEY 
    void* work( void* arg)
    {
        FILE* logHandle = NULL;
        char fileName[128] = "";
        sprintf( fileName, "Thread%d.log", static_cast<int>(pthread_self()) );
        logHandle = fopen( fileName, "w");
        pthread_setspecific( pkt, reinterpret_cast<void*>( logHandle ) );
        writeLog( "Thread starting." );
    }
    // 7, pthread_key_create( &pkt, destroy ) Create a key value identifying a location in the thread-specific      //identifying 识别
    //    data area. Each thread maintains a distinct thread-specific data area.
    //    the destroy callback function will called with the key is dectroyed
    // 8, pthread_key_delete( ) detroy the key use callback function clear the resource
    int main(int argc, char const *argv[])
    {
        pthread_key_create( &pkt, destroy );
        pthread_t pids[2] = {0};
        pthread_create( &pids[0], NULL, work, NULL );
        pthread_create( &pids[1], NULL, work, NULL );
        pthread_join( pids[0], NULL );
        pthread_join( pids[1], NULL );
        pthread_key_delete( pkt );
        printf("stop
    ");
        return 0;
    }
    

      

    ThreadLocal

    对 pthread_key_t 进行了 RAII 的封装,使用更加安全。

    #include <pthread.h>
    #include <boost/noncopyable.hpp>    // noncopyable
    #include <boost/checked_delete.hpp> // check_delete
    #include <cstdio>
    #include <cstdlib>
    #include <string>
    #include <stdexcept>
    
    template<typename T>
    class ThreadLocal : public boost::noncopyable
    {
        public:
        typedef ThreadLocal<T>* pThreadLocal;
        ThreadLocal()
        { pthread_key_create( &pkey_, &ThreadLocal::destroy ); }
    
        ~ThreadLocal()
        { pthread_key_delete( pkey_ ); }
    
        T& value()
        {
            T* pvalue = reinterpret_cast<T*>( pthread_getspecific( pkey_ ) );
            if( !pvalue )
            {
                T* obj = new T();
                pthread_setspecific( pkey_, reinterpret_cast<void*>( obj ) );
                pvalue = obj;
            }
            return *pvalue;
        }
    
        private:
        static void destroy( void* arg )
        { 
            T* obj = reinterpret_cast<T*>( arg );
            boost::checked_delete( obj );
        }
    
        pthread_key_t pkey_;
    };
    
    class Logger
    {
        public:
        Logger()
        {
            char fName[128] = "";
            sprintf(  fName, "log_%lu.log", static_cast<unsigned long>( pthread_self() ) );
            fp = fopen( fName, "w" );
            if( !fp ) throw std::runtime_error( std::string("can not create ") + fName );
        }
    
        ~Logger() { fclose( fp ); }
    
        void log( const std::string& s ) { fprintf( fp, "%s
    ", s.c_str() ); }
    
        private:
        FILE* fp;
    };
    
    void* run( void* arg )
    {
        auto ptllogger  = reinterpret_cast< ThreadLocal<Logger>::pThreadLocal>( arg);
        Logger& plogger = ptllogger->value();
        plogger.log( "Hello thread local" );
    }
    
    int main()
    {
        ThreadLocal<Logger>::pThreadLocal p = new ThreadLocal<Logger>;
        Logger& plogger = p->value();
        plogger.log( "Hello thread local" );
    
        pthread_t threads[2] = {0};
        pthread_create( &threads[0], NULL, run, reinterpret_cast<void*>( p ) );
        pthread_create( &threads[1], NULL, run, reinterpret_cast<void*>( p ) );
        pthread_join( threads[0], NULL );
        pthread_join( threads[1], NULL );
        delete p;
    }
    

      需要 打开原始连接 看看

  • 相关阅读:
    show proceslist时发现大量的sleep,有什么风险吗,该如何处理?
    监控MySQL的性能,应该主要观察那几个监控项?
    MySQL所有的压力都在一个CPU核心上,为什么会产生这种现象,改如何解决?
    大表,某列无索引,先需要查询该列,删除符合条件的记录,大约占40%数据量,请问有何更好的方案吗?
    MySQL DBA运维中那些动作属于危险性操作?
    云环境上自建MySQL,有哪些高可用实现方案?
    RDS上,MySQL实例中某张表数据小于tmp_table_size,但有查询时会报错临时空间满 The table '/data/mysql/zst/tmp/#sql_13975_23' is full. 原因可能是什么?
    MySQL误删除frm文件该怎么办?
    生产环境MySQL死锁如何监控及如何减少死锁发生的概率。
    MongoDB有哪些优秀特性及适合的场景是什么?
  • 原文地址:https://www.cnblogs.com/zhangkele/p/10751377.html
Copyright © 2020-2023  润新知