pthread的TLS(THREAD LOCAL STORAGE)

来源:互联网 发布:淘宝详情分割线 编辑:程序博客网 时间:2024/05/22 02:24

TLS全称为Thread Local Storage,是系统为解决一个进程中多个线程同时访问全局变量而提供的机制,保证数据的完整性与正确性,也可以称为 Thread Specific Data ,即表面上看起来这是一个全局变量,所有线程都可以使用它,而它的值在每一个线程中又是单独存储的,在linux中主要有pthread_key实现

pthread _key接口介绍

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *))

该函数从TSD池中分配一项,将其值赋给key供以后访问使用。如果destr_function不为空,在线程退出(pthread_exit())时将以key所关联的数据为参数调用destr_function(),以释放分配的缓冲区。

不论哪个线程调用pthread_key_create(),所创建的key都是所有线程可访问的,但各个线程可根据自己的需要往key中填入不同的值,这就相当于提供了一个同名而不同值的全局变量。


注销一个TSD采用如下API:

int pthread_key_delete(pthread_key_t key)

这个函数并不检查当前是否有线程正使用该TSD,也不会调用清理函数(destr_function),而只是将TSD释放以供下一次调用pthread_key_create()使用。在LinuxThreads中,它还会将与之相关的线程数据项设为NULL(见"访问")。


TSD的读写都通过专门的Posix Thread函数进行,其API定义如下:

int pthread_setspecific(pthread_key_t key, const void *pointer)

 void * pthread_getspecific(pthread_key_t key)

写入(pthread_setspecific())时,将pointer的值(不是所指的内容)与key相关联,而相应的读出函数则将与key相关联的数据读出来。数据类型都设为void *,因此可以指向任何类型的数据。


例子:

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<jni.h>#include<signal.h>#include<sys/time.h>#include<pthread.h> #include <fcntl.h>#include <sys/types.h>#include <sys/epoll.h>#include <limits.h>#include<android/log.h>#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))#ifndef NELEM# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))#endifstatic char CLASS_NAME[] = "com/sailor/Pthread";static pthread_key_t gTLSKey = 0; // thread local storagepthread_once_t initonce = PTHREAD_ONCE_INIT;static void threadDestructor(void *st){// 线程退出,销毁数据  LOGE("Destroy pthread key");}static void *init_routine(void *st){sleep(1);LOGE("poll_once");int tid = pthread_self();LOGE("poll_once Thread:%d", tid);pthread_setspecific(gTLSKey, (void *)1);LOGE("poll_once Thread:%d return %d", tid, (int)pthread_getspecific(gTLSKey));}static void *child1(void *arg1){int error;LOGE("child1");int tid = pthread_self();LOGE("child1 Thread:%d", tid);pthread_setspecific(gTLSKey, (void *)tid);LOGE("child1 Thread:%d return %d", tid, (int)pthread_getspecific(gTLSKey));sleep(5);LOGE("child1 Thread:%d return %d", tid, (int)pthread_getspecific(gTLSKey));}static int CreateThread(){int result = pthread_key_create(&gTLSKey, threadDestructor);if(result != 0){LOGE("Could not allocate TLS key.");}return result;}static void Start(){int tid;int error;pthread_create(&tid, NULL, child1, NULL);pthread_create(&tid, NULL, init_routine, NULL);// 只执行一次,下回调用不会执行init_routine       /* if (error = pthread_once(&initonce, init_routine)) {              LOGE("pthread_once: %d\r\n",error);                       }else{LOGE("poll_once pthread start");}*/}static int DestroyThread(){pthread_key_delete(gTLSKey);}static JNINativeMethod mehods[] = {{ "createThread", "()I", (void *) CreateThread },{ "destroyThread", "()I", (void *) DestroyThread },{ "start", "()V", (void *) Start }};static int registerNativeMethods(JNIEnv *env, const char* className,                                 const JNINativeMethod* methods, int numMethods){    int rc;    jclass clazz;    clazz = (*env)->FindClass(env, className);    if (clazz == NULL) {        LOGE("Native registration unable to find class '%s'\n", className);        return -1;    }    if (rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods)) < 0) {        LOGE("RegisterNatives failed for '%s' %d\n", className, rc);        return -1;    }    return 0;}static int register_jni(JNIEnv *env){return registerNativeMethods(env, CLASS_NAME, mehods, NELEM(mehods));}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){     JNIEnv* env = NULL;     jint result = -1;          //获取JNI版本     if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)      {         LOGE("GetEnv failed!");             return result;     }     if (register_jni(env) < 0) {LOGE("register method failed!");             return result;     }     return JNI_VERSION_1_4;}

java类:

package com.sailor;import android.util.Log;public class Pthread {static {// 加载动态库System.loadLibrary("JNIPthread");}public native int createThread();public native void start();public native int destroyThread();}


调用
public void startTLS(View view){pthread = new Pthread();Log.d("jacklam", "create thread");pthread.createThread();Log.d("jacklam", "start thread");pthread.start();/*Log.d("jacklam", "destroy thread");*//*pthread.destroyThread();*/}


结果:

10-15 11:36:23.348: D/jacklam(7868): create thread10-15 11:36:23.348: D/jacklam(7868): start thread10-15 11:36:23.348: E/native-activity(7868): child110-15 11:36:23.348: E/native-activity(7868): child1 Thread:2399354410-15 11:36:23.348: E/native-activity(7868): child1 Thread:23993544 return 2399354410-15 11:36:24.359: E/native-activity(7868): poll_once10-15 11:36:24.359: E/native-activity(7868): poll_once Thread:2311934410-15 11:36:24.359: E/native-activity(7868): poll_once Thread:23119344 return 110-15 11:36:24.359: E/native-activity(7868): Destroy pthread key10-15 11:36:28.353: E/native-activity(7868): child1 Thread:23993544 return 2399354410-15 11:36:28.353: E/native-activity(7868): Destroy pthread key


可以从结果里面看出,两个线程的值互不干扰


0 0