转自: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. 迭代器Iterator与语法糖for-each

    一.为什么需要迭代器 设计模式迭代器 迭代器作用于集合,是用来遍历集合元素的对象.迭代器迭代器不是Java独有的,大部分高级语言都提供了迭代器来遍历集合.实际上,迭代器是一种设计模式: 迭代器模式提供 ...

  2. Python 列表元素分组,比如 [1,2,3,...20]变成 [[1,2,3],[4,5,6]....](列表生成式解决)

    # 生成一个1到20的列表 a=[x for x in range(1,21)] # 把a列表切片,并赋值给b列表,x为0到20且步长为3的列表,在这里具体为[0,3,6,9,12,15,18] # ...

  3. f触发器、存储过程

    drop trigger trig_insert--删除触发器

  4. UVALive 4685 Succession 树DP+背包

    一.前言 这道题同样来自于红书P142,作为树DP专题中的一道比较难的题目,A了一天左右的时间,看上去事实证明,这题的难度理我本身的实力还是有些太远了,于是正确的做法应该是分析一下题目之后进行解析什么 ...

  5. 读书笔记jvm探秘之二: 对象创建

    对象是面向对象设计语言无法回避的东西,可见其重要性,JAVA的对象相较于C++来说,不算很复杂,但是我们看到一句话背后往往有很多东西值得探讨(NEW关键字). 对象如何被创建? 首先一句简单的NEW语 ...

  6. MSSQL将多行单列变一行一列并用指定分隔符分隔,模拟Mysql中的group_concat

    -- 将多行记录(只能一个列)用指定分隔符分隔 IF(OBJECT_ID('sp_RowsChangeClosBySplit',N'P') IS NOT NULL) DROP PROC sp_Rows ...

  7. 设计模式之第14章-命令模式(Java实现)

    设计模式之第14章-命令模式(Java实现) “小明,滚出去.”“小明,这个问题怎么做?”(可怜的小明无奈躺枪.小明:老师,我和你有什么仇什么怨,我和你有什么仇什么怨啊到底...老师:小明,滚出去.习 ...

  8. 14、响应式布局和BootStrap 全局CSS样式知识点总结-part1

    1.什么是响应式布局 响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,这个概念是为解决移动互联网浏览而诞生的. 简而言之,就是一个网站能够兼容多个终端——而不是为每个终端做一 ...

  9. 45、gridview在改变位置之后无法完整显示的问题记录

    gridview的父布局为layoutFather,gridview id为 layoutGridview layoutFather   高度设置为130dp layoutGridview高度设置为1 ...

  10. 【Palindrome Number】cpp

    题目: Determine whether an integer is a palindrome. Do this without extra space. click to show spoiler ...