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])))
#endif
static char CLASS_NAME[] = "com/sailor/Pthread";
static pthread_key_t gTLSKey = 0; // thread local storage
pthread_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 thread
10-15 11:36:23.348: D/jacklam(7868): start thread
10-15 11:36:23.348: E/native-activity(7868): child1
10-15 11:36:23.348: E/native-activity(7868): child1 Thread:23993544
10-15 11:36:23.348: E/native-activity(7868): child1 Thread:23993544 return 23993544
10-15 11:36:24.359: E/native-activity(7868): poll_once
10-15 11:36:24.359: E/native-activity(7868): poll_once Thread:23119344
10-15 11:36:24.359: E/native-activity(7868): poll_once Thread:23119344 return 1
10-15 11:36:24.359: E/native-activity(7868): Destroy pthread key
10-15 11:36:28.353: E/native-activity(7868): child1 Thread:23993544 return 23993544
10-15 11:36:28.353: E/native-activity(7868): Destroy pthread key