摘要:
pthread线程局部数据-记录
参考:
https://www.akkadia.org/drepper/tls.pdf
https://en.wikipedia.org/wiki/Thread-local_storage
https://download.csdn.net/download/adofsauron/87408865
测试代码:
示例一:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_key_t key;
struct args {
char *msg;
};
void print_msg(char *msg) {
int *tl = (int *)pthread_getspecific(key);
printf("msg: %s, tl: %d\n", msg, *tl);
}
void *exec_in_thread(struct args *args) {
int *tl = malloc(sizeof(int));
*tl = 5;
pthread_setspecific(key, tl);
print_msg(args->msg);
sleep(2);
*tl = 4;
print_msg(args->msg);
pthread_setspecific(key, NULL);
free(tl);
pthread_exit(NULL);
}
int main() {
int i = 0, num_threads = 10;
pthread_t threads[num_threads];
struct args *my_args = malloc(sizeof(struct args));
my_args->msg = "some message...";
pthread_key_create(&key, NULL);
for(i = 0; i<num_threads; i++) {
pthread_create(&threads[i], NULL, exec_in_thread, my_args);
}
for(i = 0; i<num_threads; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
示例二:
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_THREADS 2
#define ERROR(func, no) { \
fprintf(stderr, "%s: %s\n", func, strerror(no)); \
exit(EXIT_FAILURE); \
}
pthread_key_t key_tsd;
typedef struct tsd {
pthread_t tid; // thread ID
char *str; //
} tsd_t;
pthread_once_t once_control = PTHREAD_ONCE_INIT;
void destory_routine(void* value) {
printf("destory ...\n");
free(value); //delete dynamic storage allocated to each TSD
}
void init_routine() {
int ret;
ret = pthread_key_create(&key_tsd, destory_routine);
if(ret) {
ERROR("pthread_key_create", ret);
}
printf("Thread-specified data key initialized\n");
}
void* thread_routine(void *arg) {
//key will be initialized twice
//pthread_once_t once_control = PTHREAD_ONCE_INIT;
pthread_once(&once_control, init_routine); // make sure initialization actually only run once
pthread_t tid = pthread_self();
tsd_t* val = (tsd_t*)malloc(sizeof(tsd_t));
val->tid = tid;
val->str = (char*)arg;
pthread_setspecific(key_tsd, val);
printf("Thread %#lx set thread-specific data: %p\n",
(size_t)tid, val);
val = pthread_getspecific(key_tsd);
printf("Thread %#lx get thread-specific data: %s\n",
(size_t)val->tid, val->str);
sleep(2);
val = pthread_getspecific(key_tsd);
printf("Thread %#lx get thread-specific data: %s\n",
(size_t)val->tid, val->str);
pthread_exit(NULL);
}
int main(int argc, char** argv)
{
int ret, i;
pthread_t tid[NUM_THREADS];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if((ret=pthread_create(&tid[0], &attr, thread_routine, "Thread 1"))){
ERROR("pthread_create", ret);
}
if((ret=pthread_create(&tid[1], &attr, thread_routine, "Thread 2"))){
ERROR("pthread_create", ret);
}
pthread_attr_destroy(&attr);
for(i=0; i<NUM_THREADS; ++i) {
ret = pthread_join(tid[i], NULL);
if(ret) {
ERROR("pthread_join", ret);
}
}
pthread_key_delete(key_tsd);
exit(EXIT_SUCCESS);
}
运行结果分析:
从程序的运行结果可以看出:两线程通过相同的可以访问到本线程的特定数据,并且程序中特意 sleep 一段时间后再次访问 TSD 结果不变,进一步验证 TSD 的特性。值得注意的是上述程序中调用了 pthread_once 函数来创建 pthread_key_t
变量,程序的运行结果可以发现该 key 只被初始化了一次,这是通过设置 pthread_once 函数的 once_control 参数实现的,而且要注意该参数的生存周期应为整个程序的运行周期,也就是说该参数应是一个全局变量或静态局部变量。而 destroy_routine 调用了两次,释放了各自线程为 TSD分配的动态内存。
once_control为局部变量, key被初始化两次:
示例三: __thread关键字
#include<iostream>
#include<pthread.h>
#include <unistd.h>
#define D "-----------------------------------------"
using namespace std;
static __thread int a=12;
void *thread1(void *arg);
void *thread2(void *arg);
int main()
{
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,thread1,NULL);
pthread_create(&pid2,NULL,thread2,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
cout<<"main_a="<<a<<" "<<"addr_a="<<&a<<endl;
}
void *thread1(void *arg)
{
cout<<"I am thread1"<<endl;
cout<<"a="<<a<<" "<<&a<<endl;
sleep(1);
a=1;
cout<<"thread1->a="<<a<<" "<<"addr_a="<<&a<<endl;
cout<<D<<endl;
return NULL;
}
void *thread2(void *arg)
{
cout<<"I am thread2"<<endl;
cout<<"a="<<a<<" "<<&a<<endl;
a=2;
cout<<"thread2->a="<<a<<" "<<"addr_a="<<&a<<endl;
cout<<D<<endl;
return NULL;
}
分析:
该程序为了测试这个关键字的作用;
介绍一下程序,
首先在一开始定义一个全局变量a=12,其次声明连个线程的回调函数这两个函数作用,
用于先打印一下a的值然后再改变在打印a的值,至于为什么这样做,是想验证一下他是不是写时拷贝,
然后主程序就是开辟两个线程并等待其完成最后再打印一下a的值及地址来确定主线程是否有影响;
最终分析:
通过结果我们可以看到这个关键字作用是,只要其他线程用它他会直接在自己的线程栈上创建该对象并保留其原有的值;
不会干扰其他线程中的该值;