`
ipjmc
  • 浏览: 702758 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Linux线程私有数据

阅读更多

        线程私有数据的使用场景是:某个函数在第一次被调用的时候,分配内存block,在以后每次调用的时候,都是用第一次所分配的内存block,无需再次分配。可以用线程私有数据来存储这个内存block。
        在多线程环境下,如果不使用线程私有数据,由于函数只分配了一个block,所以各个线程在block上必然会有竞争。如果每个线程对这个block的使用是相互独立的,比如对errno的设置,就可以使用线程私有变量来避免竞争。
        可以把线程私有变量看成是一种<key, value>类型的数据结构,对于同一个key,不同的线程可以有不同的value。Linux为这种数据结构提供了GET和SET接口,即:

void *pthread_getspecific(pthread_key_t key);//获取key所对应的线程私有数据
​int pthread_setspecific(pthread_key_t key, const void *value); //设置key所对应的线程私有数据


        一般而言,比如key是全局变量,需要通过pthread_key_create(&key, destructor)初始化key。线程1调用pthread_setspecific(key, value1);设置了key所对应的值value1。这种设置在另外一个线程2是不可见的,即线程2通过pthread_getspecific(key)是获取不到value1的。同样线程2通过pthread_setspecific(key, value2)对线程1也没有任何影响。

        总的来说,就是对于同一个pthread_key,每个线程都对value有一个独立的副本,所以避免了竞争。
        具体例子如下,例子来源于《The Linux Programming Interface - A Linux and UNIX System Programming Handbook》:

#include <stdio.h>
#include <string.h> /* Get declaration of strerror() */
#include <pthread.h>

static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t strerrorKey;
#define MAX_ERROR_LEN 256 /* Maximum length of string in per-thread
                             buffer returned by strerror() */

/* Free thread-specific data buffer */
static void destructor(void *buf) {
    free(buf);
}

/* One-time key creation function */
static void createKey(void) {
    int s;
    /* Allocate a unique thread-specific data key and save the address
       of the destructor for thread-specific data buffers */
    e s = pthread_key_create(&strerrorKey, destructor);
    if (s != 0)
        errExitEN(s, "pthread_key_create");
}

char * strerror(int err) {
    int s;
    char *buf;
    /* Make first caller allocate key for thread-specific data */
    r s = pthread_once(&once, createKey);
    if (s != 0)
        errExitEN(s, "pthread_once");
    t buf = pthread_getspecific(strerrorKey);
    if (buf == NULL) { /* If first call from this thread, allocate
                          buffer for thread, and save its location */
        y buf = malloc(MAX_ERROR_LEN);
        if (buf == NULL)
            errExit("malloc");
        u s = pthread_setspecific(strerrorKey, buf);
        if (s != 0)
            errExitEN(s, "pthread_setspecific");
    }
    if (err < 0 || err >= _sys_nerr || _sys_errlist[err] == NULL) {
        snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err);
    } else {
        strncpy(buf, _sys_errlist[err], MAX_ERROR_LEN - 1);
        buf[MAX_ERROR_LEN - 1] = '\0'; /* Ensure null termination */
    }
    return buf;
}


        thread local和线程私有数据在概念上差不多,thread local为线程私有数据提供了更方便的访问接口。
        如下例子

static __thread char local_buf[MAX_ERROR_LEN];


        定义static变量local_buf,通过__thread修饰,则每个线程都对local_buf,都会有一个独立的副本,它们自己不会相互干扰
        通过如下程序的输出,我们可以看到,不同的线程local_buf的地址是不同的,所以每个线程可以独立的对buf修改。


#include <stdio.h>
#include <string.h>
#include <pthread.h>

#define MAX_ERROR_LEN 10240

static char normal_buf[MAX_ERROR_LEN];
static __thread char local_buf[MAX_ERROR_LEN];

void * func(void * arg) {
    printf("thread %x : local_buf %x\n", pthread_self(), local_buf);
    printf("thread %x : normal_buf %x\n", pthread_self(), normal_buf);
}

int main() {

    pthread_t tid;
    pthread_create(&tid, NULL, func, NULL);

    func(NULL);
    pthread_join(tid, NULL);
    return 0;
}
分享到:
评论

相关推荐

    线程私有数据示例代码

    Linux系统编程——线程私有数据,相关教程链接如下: http://blog.csdn.net/tennysonsky/article/details/46452953

    linux多线程编程

    linux多线程编程 声明:本文是网上整理的资料,版权属其作者本人所有。 1 第一章 线程基础知识 2 一.什么是线程 2 二.线程的优点 2 三.线程的缺点 2 四.线程的结构 2 五.线程标识 2 六.线程的创建 3 七..线程...

    Linux系统编程——线程私有数据-附件资源

    Linux系统编程——线程私有数据-附件资源

    第3章_linux多线程编程

    2、线程包含了表示进程内执行环境必须的信息,包括线程ID、一组寄存器、栈、调度优先级、策略、信号屏蔽字、errno变量、线程私有数据。 3、测试是否支持POSIX线程: 使用编译测试宏_POSIX_THREADS 调用sysconf,运行...

    linux多线程编程(五)

    同时线程也有其私有的数据信息,包括:线程号、寄存器(程序计数器和堆栈指针)、堆栈、信号掩码、优先级、线程私有存储空间。  为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统...

    关于Linux线程的线程栈以及TLS

    本文挑选了原则上是每线程私有的地址空间来讨论,分别是线程栈和TLS。原则山私有并不是真的私有,因为大家都知道线程的特点就是共享地址空间,原则私有空间就是一般而言通过正常手段其它线程不会触及这些空间的数据...

    linux系统下多线程编程文档资料

    九、线程的私有数据 9 第二章 线程高级知识 11 一.线程属性 11 二、线程的分离状态 12 三、线程的继承性 13 四、线程的调度策略 13 五、线程的调度参数 14 六、线程的作用域 16 七、线程堆栈的大小 17 八、线程堆栈...

    QT/C++多线程练习:单生产者多消费者(源码)

    涉及 线程创建与退出、线程暂停、父子线程之前以及兄弟线程之间的参数和信号传递、多线程的以及多线程的管理。要求是练习的demo对于以上的点只要涉及基础即可。 主线程、生产者线程(一)、消费者管理线程(一)、...

    Posix线程编程指南.rar

    线程私有数据 3.1概念及作用 3.2创建和注销 4.线程同步 4.1互斥锁 4.1.1 创建和销毁 4.1.2互斥锁属性 4.1.3锁操作 4.1.4其他 4.2条件变量 4.2.1创建和注销 4.2.2等待和激发 ...

    Posix线程编程指南

    线程私有数据 3.1概念及作用 3.2创建和注销 4.线程同步 4.1互斥锁 4.1.1 创建和销毁 4.1.2互斥锁属性 4.1.3锁操作 4.1.4其他 4.2条件变量 4.2.1创建和注销 ......................

    UNIX环境高级编程_第二版中文

    12.6 线程私有数据  12.7 取消选项  12.8 线程和信号  12.9 线程和fork  12.10 线程和I/O  12.11 小结  习题  第13章 守护进程  13.1 引言  13.2 守护进程的特征  13.3 编程规则  13.4 出错...

    UNIX环境高级编程_第2版.part1

    12.6 线程私有数据328 12.7 取消选项331 12.8 线程和信号333 12.9 线程和fork 336 12.10 线程和i/o 339 12.11 小结340 习题340 第13章守护进程341 13.1 引言341 13.2 守护进程的特征341 13.3 编程规则342 ...

    UNIX环境高级编程_第2版.part2

    12.6 线程私有数据328 12.7 取消选项331 12.8 线程和信号333 12.9 线程和fork 336 12.10 线程和i/o 339 12.11 小结340 习题340 第13章守护进程341 13.1 引言341 13.2 守护进程的特征341 13.3 编程规则342 ...

    UNIX环境高级编程

    12.6 线程私有数据328 12.7 取消选项331 12.8 线程和信号333 12.9 线程和fork 336 12.10 线程和I/O 339 12.11 小结340 习题340 第13章守护进程341 13.1 引言341 13.2 守护进程的特征341 13.3 编程规则342 13.4 出错...

    UNIX环境高级编程(第二版中文)

    12.6 线程私有数据 328 12.7 取消选项 331 12.8 线程和信号 333 12.9 线程和fork 336 12.10 线程和I/O 339 12.11 小结 340 习题 340 第13章 守护进程 341 13.1 引言 341 13.2 守护进程的特征 341...

    unix环境编程电子书

    313 12.3 线程属性 314 12.4 同步属性 318 12.5 重入 324 12.6 线程私有数据 328 12.7 取消选项 331 12.8 线程和信号 333 12.9 线程和fork 336 12.10 线程和I/O 339 12.11 小结 340 习题 340 第...

Global site tag (gtag.js) - Google Analytics