转自:http://blog.csdn.net/kkxgx/article/details/7513278

版权声明:本文为博主原创文章,未经博主允许不得转载。

一,一次性初始化

以保证线程在调用资源时,确保资源已经被初始化,并且只初始化一次。

在传统的顺序编程中,一次性初始化经常通过使用布尔变量来管理。控制变量被静态初始化为0,而任何依赖于初始化的代码都能测试该变量。如果变量值仍然为0,则它能实行初始化,然后将变量置为1。以后检查的代码将跳过初始化。

但是在多线程程序设计中,事情就变的复杂的多。如果多个线程并发地执行初始化序列代码,2个线程可能发现控制变量为0,并且都实行初始话,而该过程本该仅仅执行一次。初始化的状态必须由互斥量保护。之所以使用pthread_once,主要原因是原来不能静态的初始化一个互斥量,这样如果要使用一个互斥量,必须调用pthread_mutex_init函数初始化互斥量,并且必须仅仅初始化一次,因此初始化调用应该在一次性初始化代码中完成,pthread_once就解决在多线程环境中使得互斥量和初始化代码都仅仅被初始化一次的问题;

[cpp] view plain copy

    #include <pthread.h>
pthread_once_t once_control=PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));
init_routine 初始化函数 实例代码如下:
[cpp] view plain copy #include <pthread.h>
#include <stdio.h>
pthread_once_t once_block = PTHREAD_ONCE_INIT;
pthread_mutex_t mutex; /*
* This is the one-time initialization routine. It will be
* called exactly once, no matter how many calls to pthread_once
* with the same control structure are made during the course of
* the program.
*/
void once_init_routine (void)
{
int status; status = pthread_mutex_init (&mutex, NULL);
if (status != )
printf("error Init Mutex");
} /*
* Thread start routine that calls pthread_once.
*/
void *thread_routine (void *arg)
{
int status; status = pthread_once (&once_block, once_init_routine);
if (status != )
printf("error Once init");
status = pthread_mutex_lock (&mutex);
if (status != )
printf("error Lock mutex");
printf ("thread_routine has locked the mutex.\n");
status = pthread_mutex_unlock (&mutex);
if (status != )
printf("error Unlock mutex");
return NULL;
} int main (int argc, char *argv[])
{
pthread_t thread_id;
char *input, buffer[];
int status; status = pthread_create (&thread_id, NULL, thread_routine, NULL);
if (status != )
printf("error Create thread");
status = pthread_once (&once_block, once_init_routine);
if (status != )
printf("error Once init");
status = pthread_mutex_lock (&mutex);
if (status != )
printf("error Lock mutex");
printf ("Main has locked the mutex.\n");
status = pthread_mutex_unlock (&mutex);
if (status != )
printf("error Unlock mutex");
status = pthread_join (thread_id, NULL);
if (status != )
printf("error Join thread");
return ;
} 程序输出: Main has locked the mutex.
thread_routine has locked the mutex. 二,线程私有数据 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据。在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问,比如程序可能需要每个线程维护一个链表,而使用相同的函数操作,最简单的办法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由Posix线程库维护,称为线程私有数据(Thread-specific Data,或TSD)。 )建立线程私有数据
[cpp] view plain copy pthread_key_t key;
int pthread_key_create(pthread_key *key,void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key); 该函数从TSD池中分配一项,将其值赋给key供以后访问使用。如果destr_function不为空,在线程退出(pthread_exit())时将以key所关联的数据为参数调用destr_function(),以释放分配的缓冲区。不论哪个线程调用pthread_key_create(),所创建的key都是所有线程可访问的,但各个线程可根据自己的需要往key中填入不同的值,这就相当于提供了一个同名而不同值的全局变量. pthread_key_delete这个函数并不检查当前是否有线程正使用该TSD,也不会调用清理函数(destr_function),而只是将TSD释放以供下一次调用pthread_key_create()使用。因为只有你肯定没有线程持有该键值时,才能删除线程私有数据键,故通常的做法是不释放线程私有数据键。 )使用线程私有数据 [cpp] view plain copy int pthread_setspecific(pthread_key_t key, const void *value)
void * pthread_getspecific(pthread_key_t key) 可以使用pthread_getspecific函数来获取线程当前键值,或通过第一个函数改变当前的键值。
[cpp] view plain copy /*
* tsd_once.c
*
* Demonstrate use of pthread_once to initialize something
* exactly once within a multithreaded program.
*
* Note that it is often easier to use a statically initialized
* mutex to accomplish the same result.
*/
#include <pthread.h>
#include <stdio.h> /*
* Structure used as the value for thread-specific data key.
*/
typedef struct tsd_tag {
pthread_t thread_id;
char *string;
} tsd_t; pthread_key_t tsd_key; /* Thread-specific data key */
pthread_once_t key_once = PTHREAD_ONCE_INIT; /*
* One-time initialization routine used with the pthread_once
* control block.
*/
void once_routine (void)
{
int status; printf ("initializing key\n");
status = pthread_key_create (&tsd_key, NULL);
if (status != )
printf("error Create key");
}
/*
* Thread start routine that uses pthread_once to dynamically
* create a thread-specific data key.
*/
void *thread_routine (void *arg)
{
tsd_t *value;
int status; status = pthread_once (&key_once, once_routine);//一次性初始化
if (status != )
printf("error Once init");
value = (tsd_t*)malloc (sizeof (tsd_t));
if (value == NULL)
printf("error Allocate key value");
status = pthread_setspecific (tsd_key, value);
if (status != )
printf("error Set tsd");
printf ("%s set tsd value %p\n", arg, value);
value->thread_id = pthread_self ();
value->string = (char*)arg;
value = (tsd_t*)pthread_getspecific (tsd_key);
printf ("%s starting...\n", value->string);
sleep ();
value = (tsd_t*)pthread_getspecific (tsd_key);
printf ("%s done...\n", value->string);
return NULL;
} void main (int argc, char *argv[])
{
pthread_t thread1, thread2;
int status; status = pthread_create (
&thread1, NULL, thread_routine, "thread 1");
if (status != )
printf("error Create thread 1");
status = pthread_create (
&thread2, NULL, thread_routine, "thread 2");
if (status != )
printf("error Create thread 2");
pthread_exit;
} 运行结果如下: thread set tsd value 0x9de24f0
thread starting...
thread set tsd value 0x9de2500
thread starting...
thread done...
thread done... 部分内容摘自:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part2/
http://blog.chinaunix.net/uid-20627834-id-3005052.html

linux多线程学习笔记六--一次性初始化和线程私有数据【转】的更多相关文章

  1. 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier

    目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...

  2. linux多线程学习笔记五--线程安全【转】

    转自:http://blog.csdn.net/kkxgx/article/details/7506085 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,线程安全基础 一个函数被称为线程安 ...

  3. linux初级学习笔记六:linux用户及权限详解!(视频序号:03_4)

    本节学习的命令:/etc/passwd,/etc/shadow,/etc/group文件详解 本节学习的技能: 安全上下文 文件与目录的权限管理 影子命令 用户,用户组类别详解 /etc/passwd ...

  4. Docker学习笔记六:Docker搭建企业级私有仓库

    前言 Docker不仅是一个强大的服务器部署工具,而且它还有一个官方的Docker Hub registry用于储存Docker镜像.上传镜像到Docker Hub是免费的,上传的镜像文件同时也对公共 ...

  5. SpringMVC学习笔记六:使用 hibernate-validator注解式数据校验

    对客户端传过来的参数,在使用前一般需要进行校验. SpringMVC框架内置了Validator验证接口,但是实现起来太麻烦.我们一般使用 hibernate-validator进行数据校验. 1:j ...

  6. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  7. 尚硅谷韩顺平Linux教程学习笔记

    目录 尚硅谷韩顺平Linux教程学习笔记 写在前面 虚拟机 Linux目录结构 远程登录Linux系统 vi和vim编辑器 关机.重启和用户登录注销 用户管理 实用指令 组管理和权限管理 定时任务调度 ...

  8. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  9. 多线程学习笔记九之ThreadLocal

    目录 多线程学习笔记九之ThreadLocal 简介 类结构 源码分析 ThreadLocalMap set(T value) get() remove() 为什么ThreadLocalMap的键是W ...

随机推荐

  1. GoF23种设计模式之创建型模式之工厂方法模式

    一.概述 定义一个用于创建对象的接口,让子类去决定实例化哪个类.工厂方法将一个类的实例化延迟至其子类. 二.适用性 1.当一个类不知道它所必须创建的对象的类的时候. 2.当一个类希望由其子类来指定它所 ...

  2. Python之路--Python初识

    Python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程 ...

  3. 分数调查 HihoCoder - 1515

    小Hi的学校总共有N名学生,编号1-N.学校刚刚进行了一场全校的古诗文水平测验. 学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分. 小Hi想知道利用这 ...

  4. MySQL创建数据库及用户

    create database ${db_name} default charset utf8 COLLATE utf8_general_ci; grant all on ${db_name}.* t ...

  5. P3116 [USACO15JAN]会议时间Meeting Time

    P3116 [USACO15JAN]会议时间Meeting Time 题目描述 Bessie and her sister Elsie want to travel from the barn to ...

  6. MongoDB快速入门学习笔记8 MongoDB的java驱动操作

    import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.bson.D ...

  7. Python+Selenium练习篇之14-获取当前页面的title

    前面文章介绍了如何获取当前页面的URL的值,本文介绍如何获取当前页面的title,这个也可以作为测试结果的依据,通过得到的title和预期的值对比,可以支持我们判断页面跳转正确. 相关脚本代码如下: ...

  8. 如何解决Jmeter导出的聚合报告是乱码易位问题

    在使用Jmeter这个工具的时候,有些单词不懂是什么意思,就切换到这个工具自带的中文语言: 当我们测试完毕,导出聚合报告(Summary Report)的时候: 1.有一些第一个Title下面的中文是 ...

  9. 菜鸟之路——机器学习之HierarchicalClustering层次分析及个人理解

    这个算法.我个人感觉有点鸡肋.最终的表达也不是特别清楚. 原理很简单,从所有的样本中选取Euclidean distance最近的两个样本,归为一类,取其平均值组成一个新样本,总样本数少1:不断的重复 ...

  10. VC++中PostMessage、SendMessage和PeekMessage之间的区别

    1, PostMessage只把消息放入队列,不管其他程序是否处理都返回,然后继续执行,这是个异步消息投放函数.而SendMessage必须等待其他程序处理消息完了之后才返回,继续执行,这是个同步消息 ...