《unix高级环境编程》线程控制——线程私有数据

        进程中的所有线程都可以访问进程的整个地址空间,一个线程真正拥有的唯一私有存储是处理器寄存器,甚至栈地址也能被共享,底层实现也没有阻止这种访问。但处理线程私有数据的函数可以提高线程间数据的独立性,维护基于每个线程的数据。
        在需要一个变量时,如果所有线程共享相同的值,则可以使用静态或外部数据,就像在单线程程序中那样,但通常需要互斥量来同步跨越多个线程对共享数据的存取;如果每个线程都需要一个私有变量值,则必须在某处存储所有值,并且每个线程能够定位到属于自己的值,线程私有数据机制可以做到这一点,线程私有数据避免了与其他线程同步访问的问题。

        在分配线程私有数据之前,需要创建与该数据关联的键,然后每个线程就能独立地设定或取得自己的键值。键对所有的线程是相同的,但每个线程能将它独立的键值与共享的键关联。每个线程能在任何时间为键设置它的私有值,而不会影响到其他线程的键值。线程通常使用malloc 为线程私有数据分配内存空间,析构函数通常释放以分配的内存,如果线程没有释放内存就退出了,则会造成内存泄露。

/* 线程私有数据 */

/*
 * 函数功能:为线程私有数据创建键值;
 * 返回值:若成功则返回0,否则返回错误编码;
 * 函数原型:
 */
#include <pthread.h>

int pthread_key_create(pthread_key_t *keyp, void(*destructor)(void*));
/*
 * 说明:
 * 创建的键值存储在keyp所指向的内存单元中,这个键可以被进程中的所以线程使用,但每个线程把这个键
 * 与不同的线程私有数据地址进行关联;创建新键时,每个线程的数据地址设为null;
 * 该函数还包含一个键关联析构函数,当线程退出时,若数据地址为非null,则调用析构函数,唯一的参数就是数据地址;
 * 若destructor为null时,表示没有析构函数;
 */
/*
 * 函数功能:取消线程私有数据与键之间的关联;
 * 返回值:若成功则返回0,否则返回错误编码;
 * 函数原型:
 */
#include <pthread.h>

int pthread_key_delete(pthread_key_t *key);
       对于每个 pthread_key_t 变量只能有一个 pthread_key_create 调用与之对应,如果一个键创建了两次,第二次创建的键将覆盖第一次,第一次的键和任何线程为其设置的值都将丢失。

       

#include<pthread.h>
pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *initflag, void(*initfn)(void));
//成功则返回0,否则返回错误编号。

        initfalg 必须是一个全局变量或静态变量,而且必须初始化为PTHREAD_ONCE_INIT。它被称之为控制变量,pthread_once 的第二个参数就是与控制变量关联的函数指针,它所指的函数没有参数。
        pthread_once 首先检查控制变量,以判断是否已经完成初始化。如果完成,pthread_once 简单地返回;否则,pthread_once 调用初始化函数。如果一个线程在初始化过程中,另外的线程也调用了pthread_once,这后者将等待,直到前面的线程初始化完成。 
     

        键一旦创建,就可以用过调用pthread_setspecific函数把键和线程私有数据关联起来,可以通过pthread_getspecific函数获取线程私有数据的地址。

include <pthread.h>

void *pthread_getspecific(pthread_key_t key);

//返回值:线程私有数据值,若没有值与键关联则返回NULL

int pthread_setspecific(pthread_key_t key, const void *value);

//返回值:若成功则返回0,否则返回错误编号

测试程序:该程序的功能是输出变量名对应的值

#include "apue.h"
#include <pthread.h>

extern char **environ;
pthread_mutex_t env_mutex;

static pthread_key_t key;
static pthread_once_t init_done = PTHREAD_ONCE_INIT;

static void thread_init(void);
char *Mgetenv(const char *name);
void *fun1(void *arg);
void *fun2(void *arg);

int main()
{
    pthread_t tid1,tid2;
    int err;
    void *pret;
    err = pthread_create(&tid1,NULL,fun1,NULL);
    if(err != 0)
        err_quit("can't create thread: %s\n", strerror(err));
    err = pthread_create(&tid2,NULL, fun2,NULL);
    if(err != 0)
        err_quit("can't create thread: %s\n", strerror(err));
    pthread_join(tid1,&pret);
    printf("thread 1 exit code is: %d\n",(int)pret);
    pthread_join(tid2,&pret);
    printf("thread 2 exit code is: %d\n",(int)pret);
    exit(0);
}
static void thread_init(void)
{
    pthread_mutexattr_t attr;

    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&env_mutex,&attr);
    pthread_mutexattr_destroy(&attr);

    pthread_key_create(&key,free);
}
char *Mgetenv(const char *name)
{
    int i,len;
    char *envbuf;

    pthread_once(&init_done,thread_init);
    pthread_mutex_lock(&env_mutex);
    envbuf = (char*)pthread_getspecific(key);
    if(envbuf == NULL)
    {
        envbuf = (char*)malloc(ARG_MAX);
        if(envbuf == NULL)
        {
             pthread_mutex_unlock(&env_mutex);
             return NULL;
        }
        pthread_setspecific(key,envbuf);
    }
    len = strlen(name);
    for(i=0; environ[i] != NULL; i++)
    {
        if((strncmp(name, environ[i], len) == 0) &&
           (environ[i][len] == '='))
           {

               strcpy(envbuf, &environ[i][len+1]);
               pthread_mutex_unlock(&env_mutex);
               return envbuf;
           }
    }
    pthread_mutex_unlock(&env_mutex);
    return NULL;
}
void *fun1(void *arg)
{
    char *value;
    printf("thread 1 start...\n");
    value = Mgetenv("HOME");
    printf("HOME=%s\n",value);
    printf("thread 1 exit...\n");
    pthread_exit((void*)1);
}
void *fun2(void *arg)
{
    char *value;
    printf("thread 2 start...\n");
    value = Mgetenv("SHELL");
    printf("SHELL=%s\n",value);
    printf("thread 2 exit...\n");
    pthread_exit((void*)2);
}

参考资料:

《UNIX高级环境编程》

http://www.cnblogs.com/Anker/archive/2012/12/19/2824990.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值