Posix线程编程指南(2)

这是一个关于Posix线程编程的专栏。做者在阐明概念的基础上,将向您详细讲述Posix线程库API。本文是第2篇将向您讲述 线程的建立与取消
一.概念及做用
在单线程程序中,咱们常常要用到"全局变量"以实现多个函数间共享数据。在多线程环境下,因为数据空间是共享的,所以全局变量也为全部线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却能够跨多个函数访问,好比程序可能须要每一个线程维护一个链表,而使用相同的函数操做,最简单的办法就是使用同名而不一样变量地址的线程相关数据结构。这样的数据结构能够由Posix线程库维护,称为线程私有数据(Thread-specific Data,或TSD)。
二.建立和注销
Posix定义了两个API分别用来建立和注销TSD:
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中填入不一样的值,这就至关于提供了一个同名而不一样值的全局变量。在LinuxThreads的实现中,TSD池用一个结构数组表示:
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };
建立一个TSD就至关于将结构数组中的某一项设置为"in_use",并将其索引返回给*key,而后设置destructor函数为destr_function。
注销一个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 *,所以能够指向任何类型的数据。
在LinuxThreads中,使用了一个位于线程描述结构(_pthread_descr_struct)中的二维void *指针数组来存放与key关联的数据,数组大小由如下几个宏来讲明:
#define PTHREAD_KEY_2NDLEVEL_SIZE 32
#define PTHREAD_KEY_1STLEVEL_SIZE ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1)/PTHREAD_KEY_2NDLEVEL_SIZE)
其中在/usr/include/bits/local_lim.h中定义了PTHREAD_KEYS_MAX为1024,所以一维数组大小为32。
而具体存放的位置由key值通过如下计算获得:
idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZEidx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE
也就是说,数据存放与一个32×32的稀疏矩阵中。一样,访问的时候也由key值通过相似计算获得数据所在位置索引,再取出其中内容返回。
四.使用范例
如下这个例子没有什么实际意义,只是说明如何使用,以及可以使用这一机制达到存储线程私有数据的目的。
      
#i nclude <stdio.h>
#i nclude <pthread.h>
pthread_key_t key;
void echomsg(int t){
printf("destructor excuted in thread %d,param=%dn",pthread_self(),t);
}
void * child1(void *arg){
int tid=pthread_self();
printf("thread %d entern",tid);
pthread_setspecific(key,(void *)tid);
sleep(2);
printf("thread %d returns %dn",tid,pthread_getspecific(key));
sleep(5);
}
void * child2(void *arg){
int tid=pthread_self();
printf("thread %d entern",tid);
pthread_setspecific(key,(void *)tid);
sleep(1);
printf("thread %d returns %dn",tid,pthread_getspecific(key));
sleep(5);
}
int main(void){
int tid1,tid2;
printf("hellon");
pthread_key_create(&key,echomsg);
pthread_create(&tid1,NULL,child1,NULL);
pthread_create(&tid2,NULL,child2,NULL);
sleep(10);
pthread_key_delete(key);
printf("main thread exitn");
return 0;
}
#i nclude <stdio.h>
#i nclude <pthread.h>
pthread_key_t key;
void echomsg(int t){
printf("destructor excuted in thread %d,param=%dn",pthread_self(),t);
}
void * child1(void *arg){
int tid=pthread_self();
printf("thread %d entern",tid);
pthread_setspecific(key,(void *)tid);
sleep(2);
printf("thread %d returns %dn",tid,pthread_getspecific(key));
sleep(5);
}
void * child2(void *arg){
int tid=pthread_self();
printf("thread %d entern",tid);
pthread_setspecific(key,(void *)tid);
sleep(1);
printf("thread %d returns %dn",tid,pthread_getspecific(key));
sleep(5);
}
int main(void){
int tid1,tid2;
printf("hellon");
pthread_key_create(&key,echomsg);
pthread_create(&tid1,NULL,child1,NULL);
pthread_create(&tid2,NULL,child2,NULL);
sleep(10);
pthread_key_delete(key);
printf("main thread exitn");
return 0;
}
给例程建立两个线程分别设置同一个线程私有数据为本身的线程ID,为了检验其私有性,程序错开了两个线程私有数据的写入和读出的时间,从程序运行结果能够看出,两个线程对TSD的修改互不干扰。同时,当线程退出时,清理函数会自动执行,参数为tid。

0javascript

收藏html

xunet

33篇文章,12W+人气,0粉丝

Ctrl+Enter 发布java

发布git

取消ajax

推荐专栏更多

微服务技术架构和大数据治理实战

大数据时代的微服务之路

共18章 | 纯洁微笑

¥51.00 710人订阅
基于Python的DevOps实战

自动化运维开发新概念

共20章 | 抚琴煮酒

¥51.00 569人订阅

扫一扫,领取大礼包

0

分享
xunet
相关文章
相关标签/搜索