Chinaunix首页 | 论坛 | 博客
  • 博客访问: 161455
  • 博文数量: 115
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2016-11-28 14:16
文章分类

全部博文(115)

文章存档

2017年(36)

2016年(79)

我的朋友

分类: C/C++

2016-11-29 11:34:33

原文地址:多线程编程-线程数据 作者:zhenhuaqin

 

1、线程数据

  在单线程的程序里,有两种基本的数据:全局变量和局部变量。但在多线程程序里,还有第三种数据类型:线程数据(TSD: Thread-Specific Data)。它和全局变量很象,在线程内部,各个函数可以象使用全局变量一样调用它,但它对线程外部的其它线程是不可见的。这种数据的必要性是显而易见的。例如我们常见的变量errno,它返回标准的出错信息。它显然不能是一个局部变量,几乎每个函数都应该可以调用它;但它又不能是一个全局变量,否则在A线程里输出的很可能是B线程的出错信息。要实现诸如此类的变量,我们就必须使用线程数据。我们为每个线程数据创建一个键,它和这个键相关联,在各个线程里,都使用这个键来指代线程数据,但在不同的线程里,这个键代表的数据是不同的,在同一个线程里,它代表同样的数据内容。

和线程数据相关的函数主要有4个:创建一个键;为一个键指定线程数据;从一个键读取线程数据;删除键。

下面对各个函数进行详细的介绍:

(1) 创建线程键pthread_key_create

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

返回值:函数成功返回0。任何其他返回值都表示错误。

在进程中分配一个键值,这个键被用来表示一个线程数据项。这个键对进程中所有的线程都是可见的。刚创建线程数据键时,在所有线程中和这个键相关联的值都是NULL

函数成功返回后,分配的键放在key参数指向的内存中,必须保证key参数指向的内存区的有效性。

如果指定了解析函数destructor,那么当线程结束时并且将非空的值绑定在这个键上,系统将调用destructor函数,参数就是相关线程与这个键绑定的值。绑定在这个键上的内存块可由destructor函数释放。

 (2) 删除线程键pthread_key_delete

int pthread_key_delete(pthread_key_t key);

返回值:函数成功返回0。任何其他返回值都表示错误。

删除线程数据键。这个键占用的内存将被释放,该键再被引用将返回错误。

在调用该函数之前,程序必须释放和本线程相关联的资源,该函数不会引发线程数据键的解析函数。

(3) 设置线程数据pthread_setspecific

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

返回值:函数成功返回0。任何其他返回值都表示错误。

设置和某个线程数据键绑定在一起的线程专用数据(一般是指针)。

函数不会释放原来绑定在键上的内存,给一个键值绑定新的指针时,必须释放原指针指向的内存,否则会发生内存泄漏。

(4) 获取线程数据pthread_getspecific

void pthread_getspecific(pthread_key_t key, void **value);

无返回值。出错时value指向NULL

获取绑定在线程数据键上的值,并在指定的位置存储取来的值。

(5) 获取线程标示符pthread_self

pthread_t pthread_self(void);

返回当前线程的标示符。

(6) 比较线程pthread_equal

int pthread_equal(pthread_t tid1, pthread_t tid2);

如果tid1tid2相同,函数返回一个非0值,否则返回0

如果tid1tid2中任何一个是非法值,则返回将是不可预料的。

(7) 创建一次pthread_once

pthread_once ((pthread_once_t*once_control, void (*initroutine) (void)))

pthread_key_create一起使用,为了让这个键只被创建一次。函数pthread_once声明一个初始化函数,第一次调用pthread_once时它执行这个函数,以后的调用将被它忽略。

2.使用线程数据的例子:

  在下面的例子中,我们创建一个键,并将它和某个数据相关联。我们要定义一个函数createWindow,这个函数定义一个图形窗口(数据类型为Fl_Window *,这是图形界面开发工具FLTK中的数据类型)。由于各个线程都会调用这个函数,所以我们使用线程数据。

pthread_key_t myWinKey;     /* 声明一个键*/

void createWindow ( void ) {   /* 函数 createWindow */

 Fl_Window * win;

 static pthread_once_t once= PTHREAD_ONCE_INIT;

  pthread_once ( & once, createMyKey) ; /* 调用函数createMyKey,创建键*/

  win=new Fl_Window( 0, 0, 100, 100, "MyWindow"); /*win指向一新建窗口*/

 /* 对此窗口作一些可能的设置工作,如大小、位置、名称等*/

 setWindow(win);

 /* 将窗口指针值绑定在键myWinKey*/

 pthread_setpecific ( myWinKey, win);

}

/* 函数 createMyKey,创建一个键,并指定了destructor */

void createMyKey ( void ) {

 pthread_key_create(&myWinKey, freeWinKey);

}

/* 函数 freeWinKey,释放空间*/

void freeWinKey ( Fl_Window * win){

 delete win;

}

  这样,在不同的线程中调用函数createMyWin,都可以得到在线程内部均可见的窗口变量,这个变量通过函数pthread_getspecific得到。在上面的例子中,我们已经使用了函数pthread_setspecific来将线程数据和一个键绑定在一起。

阅读(990) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~