pthread的TLS(THREAD LOCAL STORAGE)

TLS是Thread Local Storage的缩写,用于保证多线程环境下全局变量的数据完整性。pthread_key接口是Linux中实现TLS的主要方式,它允许每个线程拥有独立的全局变量副本。当线程退出时,可以指定回调函数释放相关资源。pthread_key_create用于分配TSD,并可在线程结束时调用指定的析构函数。线程可以使用pthread_setspecific和pthread_getspecific来设置和获取TSD的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值