Chinaunix首页 | 论坛 | 博客
  • 博客访问: 993223
  • 博文数量: 200
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 2479
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 15:07
文章分类

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

2008-12-16 10:21:39

12.6 thread-specific data

各个thread是共享process的内存空间的,因此,他们对数据的访问要synchroniize。而有了thread-specifc data, 就可以保证你所处理的数据是这个thread本身所特有的,而不会影响到别的threadErrno就是这样的一个例子,我们当然想让errno只反映各个thread的出错情况,而不是整个process。这样就要求每个thread都应该有一份errno。而在thread模型里,errno的确就是被实现为thread-specifc数据。

不要以为thread-specifig的的确确实现了只能各自的thread访问,由于thread共享内存空间的本质,这些thread-specific数据其实还是可以被别的thread访问的,只不过他提供的接口,使得一般情况下不会造成跨越thread的访问。

当然,我们可以这样实现thread specifg数据:你可以自己管理一个table, tableindex是各个threadid,各个table项目里,保存每个threadthread-specifg数据,这样也可以。但是由于thread id本身可能不是用整形数据来实现的,所以它不适合做index。所以这种方法被抛弃。使用系统提供的这一套接口,我认为,它实际上也是根据当前的threadid,来查找一个表,表中保存了各个id对应的数据。用一个key来标示一个表,将查找和维护者张表的操作交给了thread库本身。降低了用户的复杂度。

 

#include

 

int pthread_key_create(pthread_key_t *keyp,

                       void (*destructor)(void *));

 

Returns: 0 if OK, error number on failure

这个函数调用一次,就会生成一个key,这个key是被所有的thread都能看到的,并且每个thread会与该key结合一个指针,指向每个threadthread-specific数据。这个指针,一般情况下,由各个thread去设置,一般都是malloc出来的空间。如果要建立一个key,这个函数只能被调用一次,为了保证不出现race condition,可以使用pthread_once函数,这个可以保证将函数调用一次的功能。

还使用了destructor来制定析构操作。即当一个thread调用pthread_exit的时候,或者return的时候,并且该key对应的本threadthread specific data指针不为空,那么就会调用这个析构函数。但是,如果你调用了exit之类的函数,就不会调用这些析构了,我个人的想法是,exit之类的函数,是标准c库的函数,由于没有执行pthread_exit函数,pthread库无法知道你要退出,所以就不能在你退出前作任何操作了。所以就不会执行析构操作。况且exit之类函数就直接将整个进程结束掉了。

这里还有一个概念:如果有多个thread specific data,那么他们会被循环检查,一一调用析构函数。如果某些析构函数又再次建立了新的thread specific data.就造成了一遍析构并没有将所有的数据释放,pthread库会自动检查是否还有没有释放的,如果有,会再次来一遍,往复下去,但是有一个上限:PTHREAD_DESTRUCTOR_ITERATIONS

 

#include

 

pthread_once_t initflag = PTHREAD_ONCE_INIT;

 

int pthread_once(pthread_once_t *initflag, void

(*initfn)(void));

 

Returns: 0 if OK, error number on failure

这就是保证一个函数只执行一次的方法,就算你在每个thread function里都调用pthread_once initfn只被执行一次。

如下是一段例子:

void destructor(void *);
 
    pthread_key_t key;
    pthread_once_t init_done = PTHREAD_ONCE_INIT;
 
    void
    thread_init(void)
    {
         err = pthread_key_create(&key, destructor);
    }
 
    int
    threadfunc(void *arg)
    {
         pthread_once(&init_done, thread_init);
         ...
    }

 

 

如下是给一个key设置thread specific数据的方法:

#include

 

void *pthread_getspecific(pthread_key_t key);

 

Returns: thread-specific data value or NULL if no value
has been associated with the key

int pthread_setspecific(pthread_key_t key, const

 void *value);

 

Returns: 0 if OK, error number on failure

 

下面我们验证在另一个thread里面,是可以修改其他threadthread specific数据的。这个例子,生成2thread,他们各自有一个specific数据。并且他们将其数据地址放到了specific_data数组里面,这样别的thread就可以访问他了。还可以修改。可以看出,thread_specific数据本身就是一套方便实用的接口,并没有什么特殊的效果。

#include

#include

#include

#include

 

static pthread_key_t key;

static pthread_once_t init_once = PTHREAD_ONCE_INIT;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* specific_data[2] ={0};

void init( )

{

       puts("this is pthread once init function, key is created");

       pthread_key_create( &key, free );

}

void* thread( void* para )

{

       pthread_once( &init_once, init );

       pthread_t t = pthread_self();

       printf("thread %d\n", t);

       char* sp = (char*)malloc( 10 );

       pthread_setspecific( key, (void*)sp );

       printf("thread %d: specific data: %d\n", (unsigned long)t, (unsigned long)sp );

      

       //store thread specific data into array

       pthread_mutex_lock(&mutex);

       int i=0;

       if ( !specific_data[0] )

              i = 0;

       else

              i = 1;

       specific_data[i] = sp;

       *sp = i;

       pthread_mutex_unlock(&mutex);

 

       if( i == 0 )

       {

              sleep(1);

 

              //after one thread sleeps, we are sure ,all thread have stored their specific data into

              //the array

              printf("thread %d, before editing, *(specific_data[0])=%d, *(specific_data[1])=%d\n",(unsigned long)t, *((char*)specific_data[0]),*((char*)specific_data[1]) );

              *((char*)specific_data[1]) = 0;

              printf("thread %d, after editing, *(specific_data[0])=%d, *(specific_data[1])=%d\n",(unsigned long)t, *((char*)specific_data[0]),*((char*)specific_data[1]) );

 

       }

       else

              sleep(10);

       pthread_exit(0);

}

 

 

int main()

{

       pthread_t t1,t2;

       void *st1, *st2;

       pthread_create( &t1, NULL, thread, NULL );

       pthread_create( &t2, NULL, thread, NULL );

 

       pthread_join( t1, &st1 );

       pthread_join( t2, &st2 );

       printf("thread %d returns %d\n", t1, (unsigned long)st1 );

       printf("thread %d returns %d\n", t2, (unsigned long )st2);

       return 0;

}

运行结果:

[shaoting@serverbj6:/user/shaoting/advanced_programming_under_unix_environment_2rd/mytest]$ ./a.out

this is pthread once init function, key is created

thread 1084229952

thread 1084229952: specific data: 135598704

thread 1094719808

thread 1094719808: specific data: 135598736

thread 1084229952, before editing, *(specific_data[0])=0, *(specific_data[1])=1

thread 1084229952, after editing, *(specific_data[0])=0, *(specific_data[1])=0

thread 1084229952 returns 0

thread 1094719808 returns 0

阅读(1295) | 评论(0) | 转发(0) |
0

上一篇:12.5 reentrancy

下一篇:12.7 cancel options

给主人留下些什么吧!~~