进程中的所有线程都可以访问进程的整个地址空间,一个线程真正拥有的唯一私有存储是处理器寄存器,甚至栈地址也能被共享,底层实现也没有阻止这种访问。但处理线程私有数据的函数可以提高线程间数据的独立性,维护基于每个线程的数据。
在需要一个变量时,如果所有线程共享相同的值,则可以使用静态或外部数据,就像在单线程程序中那样,但通常需要互斥量来同步跨越多个线程对共享数据的存取;如果每个线程都需要一个私有变量值,则必须在某处存储所有值,并且每个线程能够定位到属于自己的值,线程私有数据机制可以做到这一点,线程私有数据避免了与其他线程同步访问的问题。
对于每个
pthread_key_t
变量只能有一个
pthread_key_create
调用与之对应,如果一个键创建了两次,第二次创建的键将覆盖第一次,第一次的键和任何线程为其设置的值都将丢失。
键一旦创建,就可以用过调用pthread_setspecific函数把键和线程私有数据关联起来,可以通过pthread_getspecific函数获取线程私有数据的地址。
测试程序:该程序的功能是输出变量名对应的值
在需要一个变量时,如果所有线程共享相同的值,则可以使用静态或外部数据,就像在单线程程序中那样,但通常需要互斥量来同步跨越多个线程对共享数据的存取;如果每个线程都需要一个私有变量值,则必须在某处存储所有值,并且每个线程能够定位到属于自己的值,线程私有数据机制可以做到这一点,线程私有数据避免了与其他线程同步访问的问题。
在分配线程私有数据之前,需要创建与该数据关联的键,然后每个线程就能独立地设定或取得自己的键值。键对所有的线程是相同的,但每个线程能将它独立的键值与共享的键关联。每个线程能在任何时间为键设置它的私有值,而不会影响到其他线程的键值。线程通常使用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);
initfalg 必须是一个全局变量或静态变量,而且必须初始化为PTHREAD_ONCE_INIT。它被称之为控制变量,pthread_once 的第二个参数就是与控制变量关联的函数指针,它所指的函数没有参数。
pthread_once 首先检查控制变量,以判断是否已经完成初始化。如果完成,pthread_once 简单地返回;否则,pthread_once 调用初始化函数。如果一个线程在初始化过程中,另外的线程也调用了pthread_once,这后者将等待,直到前面的线程初始化完成。
- #include<pthread.h>
- pthread_once_t initflag = PTHREAD_ONCE_INIT;
- int pthread_once(pthread_once_t *initflag, void(*initfn)(void));
- //成功则返回0,否则返回错误编号。
- 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);
- }
本文深入探讨了进程中的线程私有数据机制,包括如何创建键、取消关联、初始化函数以及线程间的同步问题。通过实例展示了如何在多线程环境下安全地管理私有数据,以避免数据竞争和一致性问题。
5347

被折叠的 条评论
为什么被折叠?



