1.一次性初始化 
在 Linux函数列表 中描述了Linux线程中的常用函数,这里详细讲解 pthread_once 函数的功能和使用。

(1)为何有“一次性初始化概念”出现? 
其实在开发中,很多事情都仅仅需要做一次,不管是什么。在主函数中并且在调用任何其他依赖于初始化的事物之前初始化应用是最为容易的,特别是在创建任何线程之前初始化它需要的数据,如 互斥量、条件变量、线程特定数据键等。

(2)静态初始化变量也很方便,为何pthread_onc 会出现? 
Linux线程开发中,通常对于 互斥量、条件变量等都会提供两种初始化方式,分别是动态初始化和静态初始化。如:

pthread_cond_t cond;
//动态初始化: pthread_cond_init(&cond, NULL);
//静态初始化: pthread_cond_t = PTHREAD_COND_INITIALIZER; pthread_mutex_t;
//动态初始化: pthread_mutex_init(&mutex,NULL);
//静态初始化: pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;

这里之所以出现 pthread_once 的主要原因是因为之前的 Linux Phread 不支持静态地初始化一个互斥量、条件变量等 。这样,要使用一个互斥量,就不得不首先调用pthread_mutex_init 初始化互斥量。而且必须仅仅初始化互斥量一次,因此初始化调用应在一次性初始化代码中进程。pthread_once解决了这个递归的问题。当互斥量的静态初始化被加到标准中时,pthread_once作为便利功能而被保留了下来。若使用pthread_once方便,就使用它,但是不必一定要使用它。

(3)pthread_once 如何使用? 
首先,来看看 pthread_once 的函数原型: 

/*确保初始化函数INIT_ROUTINE只被调用一次,即使pthread_once使用相同的ONCE_CONTROL
*参数执行了多次.ONCE_CONTROL必须指向一个初始化为PTHREAD_ONCE_INIT的静态或外部变量.
*初始化函数可能会抛出异常,这就是为什么这个函数没有被标记为__THROW.
*/
extern int pthread_once (pthread_once_t *__once_control,
void (*__init_routine) (void)) __nonnull ((1, 2));

根据该函数的定义: 
①首先,需要声明类型为 pthread_once_t 的一个控制变量,而且该控制变量必须使用PTHREAD_ONCE_INIT宏来静态的初始化。 
②必须创建一个包含与该 “控制变量(pthread_once_t)” 相关联的所有初始化代码函数,现在线程可以在任何时间调用pthread_once,指定一个指向一个控制变量的指针和指向相关初始化函数的指针。 

pthread_once函数首先检查控制变量,以判断是否已经完成初始化。如果已经完成,pthread_once简单的返回;否则,它回去调用初始化函数(没有参数),并且记录下初始化被完成。如果在一个线程初始化的时候,另外一个线程也调用了pthread_once,则调用线程将阻塞等待,知道那个线程完成初始化后返回。换言之,当调用pthread_once成功返回时,调用总是能够肯定所有的状态已经初始化完成。

代码1 
pthread_once初始化函数 threadOnceInit的主要功能是初始化互斥量。pthread_once的使用能够确保它只被初始化一次。 
线程执行函数subThread中,在调用互斥量之前,先去调用了pthread_once,是为了保证它即使在主函数中没有被创建,它也会存在。

/*************************************************************************
* File Name: pthread_once.c
* Author: The answer
* Function: Other
* Mail: 2412799512@qq.com
* Created Time: 2018年09月09日 星期日12时06分09秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <time.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/epoll.h>
#include <sys/poll.h>
#define STRUCT_INIT(l,r) .l = r
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]\n",l,r);break;}}while(0); //宏初始化pthread_once_t控制变量
pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_mutex_t mutex ;
static const int globalVal = 10; //pthread_once初始化函数
void threadOnceInit(){ int ret = -1;
ret = pthread_mutex_init(&mutex, NULL);
CHECK_VARIABLE("pthread_mutex_init error",ret);
puts("pthread_mutex_init success.");
return;
} //子线程执行函数
void* subThread(void* param){
printf("subThread to do...\n");
int ret = -1;
ret = pthread_once(&once,threadOnceInit); CHECK_VARIABLE("pthread_once error",ret);
ret = pthread_mutex_lock(&mutex);
CHECK_VARIABLE("pthread_mutex_lock err",ret);
printf("subThread has clocked the mutex. and globalVal is: [%d]\n",globalVal);
ret = pthread_mutex_unlock(&mutex);
CHECK_VARIABLE("pthread_mutex_unlock err.",ret); return NULL;
} int main(int argc,char **argv)
{
pthread_t Tid;
int ret = -1;
ret = pthread_create(&Tid,NULL,subThread, NULL);
CHECK_VARIABLE("pthread_create err.",ret); ret = pthread_once(&once,threadOnceInit);
CHECK_VARIABLE("pthread_once err",ret); ret = pthread_mutex_lock(&mutex);
CHECK_VARIABLE("pthread_mutex_lock",ret); printf("Main func has locked the mutex.\n");
ret = pthread_mutex_unlock(&mutex);
CHECK_VARIABLE("pthread_mutex_unlock",ret); ret = pthread_join(Tid,NULL);
CHECK_VARIABLE("pthread_join",ret);
return 0;
}

编译:gcc pthread_once.c -o a -lpthread 
执行:./a 
其结果为:

pthread_mutex_init success.
Main func has locked the mutex.
subThread to do...
subThread has clocked the mutex. and globalVal is: [10]

通过其打印结果可以看到:主函数先于子线程先执行。主函数中先调用pthread_once,此时mutex互斥量成功的被初始化,然后子线程中再去调用pthread_once时候,检测到已经完成了初始化操作,则立刻返回不执行。

LINUX线程之一次性初始化(PTHREAD_ONCE)的更多相关文章

  1. linux多线程学习笔记六--一次性初始化和线程私有数据【转】

    转自:http://blog.csdn.net/kkxgx/article/details/7513278 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,一次性初始化 以保证线程在调用资源 ...

  2. [转载]Linux 线程实现机制分析

    本文转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 支持原创.尊重原创,分享知识! 自从多线程编程的概念出现在 Linux ...

  3. Linux线程-创建

    Linux的线程实现是在内核以外来实现的,内核本身并不提供线程创建.但是内核为提供线程[也就是轻量级进程]提供了两个系统调用__clone()和fork (),这两个系统调用都为准备一些参数,最终都用 ...

  4. Linux线程学习(一)

    一.Linux进程与线程概述 进程与线程 为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间.不同的线程可以存取内存中的同一个变量.所以,程序中的所有线程都可 ...

  5. Linux线程学习(二)

    线程基础 进程 系统中程序执行和资源分配的基本单位 每个进程有自己的数据段.代码段和堆栈段 在进行切换时需要有比较复杂的上下文切换   线程 减少处理机的空转时间,支持多处理器以及减少上下文切换开销, ...

  6. Linux 线程与进程,以及通信

    http://blog.chinaunix.net/uid-25324849-id-3110075.html 部分转自:http://blog.chinaunix.net/uid-20620288-i ...

  7. 【转】 Linux 线程同步的三种方法

    线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的 ...

  8. linux 线程编程详解

    1.线程的概念: 线程和进程有一定的相似性,通常称为轻量级的进程 同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等.但同一进程中的多个线程都有自身控制流 (它 ...

  9. Linux线程优先级

    转自:https://www.cnblogs.com/imapla/p/4234258.html Linux内核的三种调度策略: 1.SCHED_OTHER 分时调度策略 2.SCHED_FIFO   ...

  10. Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL

    Linux 线程实现机制分析 Linux 线程实现机制分析  Linux 线程模型的比较:LinuxThreads 和 NPTL http://www.ibm.com/developerworks/c ...

随机推荐

  1. 一篇文章带你入门HBase

    本文已收录至Github,推荐阅读 Java随想录 微信公众号:Java随想录 目录 HBase特性 Hadoop的限制 基本概念 NameSpace Table RowKey Column Time ...

  2. 【PAT】 1002 写出这个数 Rust Solution

    读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字. 输入格式: 每个测试输入包含 1 个测试用例,即给出自然数 n 的值.这里保证 n 小于 10​100​​. 输出格式: 在一行 ...

  3. 图书搜索领域重大突破!用Apache SeaTunnel、Milvus和OpenAI提高书名相似度搜索精准度和效率

    作者 | 刘广东,Apache SeaTunnel Committer 背景 目前,现有的图书搜索解决方案(例如公共图书馆使用的解决方案)十分依赖于关键词匹配,而不是对书名实际内容的语义理解.因此会导 ...

  4. Button按钮:得到鼠标焦点后自动放大,失去鼠标焦点后自动缩小_

    作用 程序设计过程中,我们经常需要增加一些动态效果,以此改善用户的使用体验.本文将介绍一种方法,动态显示按钮状态,使其得到鼠标焦点后自动放大,失去鼠标焦点后自动缩小. 效果图 先放一张原图(鼠标还未移 ...

  5. 【原创】xenomai UDD介绍与UDD用户态驱动示例

    目录 xenomai UDD与用户态驱动示例 一.UDD介绍 二.UDD原理及框架 1. 内存映射 2. 中断处理 UDD与UIO的区别 3. linux UIO与xenomai UDD框架对比 3. ...

  6. python:修改pdf的书签

    我觉得修改pdf书签总体来说最方便的方式就是: 导出pdf书签为文本文件,修改书签文本文件后再导入到pdf中. 1.直接修改pdf书签 python中比较好用的pdf处理的库是pymupdf: pip ...

  7. java中Object 类

    一. Object类简介 Object类是Java.java.lang包下的核心类,Object类是所有类的父类,任何一个类如果没有明确的继承一个父类的话,那么它就是Object的子类: (使用无需导 ...

  8. vulnhub_me and my grilfriend

    解题步骤 主机nmap扫描,开放22和80端口 访问该ip,发现只能本地访问 查看源代码,提示需要使用x-forwarded-for的请求头,可以在burp suite中每次添加一个请求头,也可以使用 ...

  9. WPF 中WebBrowser 控件的“允许阻止的内容”修复(引用本地的html页)

    解决方法:(个人理解:导致原因就是iE安全机制的问题吧).在你的HTML里面第一行加: <!-- saved from url=(0014)about:internet -->具体原因可以 ...

  10. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU启动那些事(10.A)- FlexSPI NAND启动时间(RT1170)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RT1170 FlexSPI NAND启动时间. 本篇是 i.MXRT1170 启动时间评测第四弹,前三篇分别给大家评测 ...