LINUX线程之一次性初始化(PTHREAD_ONCE)
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)的更多相关文章
- linux多线程学习笔记六--一次性初始化和线程私有数据【转】
转自:http://blog.csdn.net/kkxgx/article/details/7513278 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,一次性初始化 以保证线程在调用资源 ...
- [转载]Linux 线程实现机制分析
本文转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 支持原创.尊重原创,分享知识! 自从多线程编程的概念出现在 Linux ...
- Linux线程-创建
Linux的线程实现是在内核以外来实现的,内核本身并不提供线程创建.但是内核为提供线程[也就是轻量级进程]提供了两个系统调用__clone()和fork (),这两个系统调用都为准备一些参数,最终都用 ...
- Linux线程学习(一)
一.Linux进程与线程概述 进程与线程 为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间.不同的线程可以存取内存中的同一个变量.所以,程序中的所有线程都可 ...
- Linux线程学习(二)
线程基础 进程 系统中程序执行和资源分配的基本单位 每个进程有自己的数据段.代码段和堆栈段 在进行切换时需要有比较复杂的上下文切换 线程 减少处理机的空转时间,支持多处理器以及减少上下文切换开销, ...
- Linux 线程与进程,以及通信
http://blog.chinaunix.net/uid-25324849-id-3110075.html 部分转自:http://blog.chinaunix.net/uid-20620288-i ...
- 【转】 Linux 线程同步的三种方法
线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的 ...
- linux 线程编程详解
1.线程的概念: 线程和进程有一定的相似性,通常称为轻量级的进程 同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等.但同一进程中的多个线程都有自身控制流 (它 ...
- Linux线程优先级
转自:https://www.cnblogs.com/imapla/p/4234258.html Linux内核的三种调度策略: 1.SCHED_OTHER 分时调度策略 2.SCHED_FIFO ...
- Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL
Linux 线程实现机制分析 Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL http://www.ibm.com/developerworks/c ...
随机推荐
- STL-stack(ACM)
1.没有.clear()操作,需要手动pop() 重构函数(默认) stack<int> a; 基础操作 a.push() // 入栈 a.pop() // 弹出栈顶元素 a.empty( ...
- x.ai还是OpenAI?埃隆·马斯克的AI帝国【2】
上期内容咱们提到了埃隆马斯克的特斯拉是自动驾驶领域的领导者,大家可能近些年也都有从各类渠道听到过Tesla自动驾驶有关的新闻.不同于像包括Google子公司Waymo在内的大多数使用激光雷达来实现自动 ...
- 前端自定义弹框组件、自定义弹框内容alertView popup组件
快速实现前端自定义弹框.自定义弹框内容alertView popup组件, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12491 效果图 ...
- Linux 上的 .NET 如何自主生成 Dump
一:背景 1. 讲故事 前几天微信上有位朋友找到我,说他程序的 线程数 会偶发性瞬时飙高,让我看下大概是什么原因,截图如下: 如果这种问题每天都会出现,比较好的做法就是用 dotnet-trace 捕 ...
- vue3 安装 3d-force-graph
1.首先创建vue3的项目 2.创建好后通过开发工具打开项目并打开命令行,输入指令 npm install 3d-force-graph 安装即可 3.在使用的页面中引入 3d-force-graph ...
- .Net8的AOT引导程序BootStrap
前言 .Net8的本地预编机器码AOT,它几乎进行了100%的自举.微软为了摆脱C++的钳制,做了很多努力.也就是代码几乎是用C#重写,包括了虚拟机,GC,内存模型等等.而需要C++做的,也就仅仅是引 ...
- 打造原生 WebGL 2D 引擎:一场创意与技术的融合
打造原生 WebGL 2D 引擎:一场创意与技术的融合 1.引言 在当今数字化时代,网页的功能越来越丰富,已经远远超越了传统的文本和图片呈现.我们生活在一个充满交互性和视觉魅力的网络世界.每天都会遇到 ...
- SQL-去除最大值与最小值求均值的问题
背景 今天有同事问我一道关于数据库SQL的面试题,我刚开始随便给了一个思路,后来思索发现这个思路有漏洞,于是总结下来,仅供参考. 问题: 薪水表中是员工薪水的基本信息,包括雇员编号,和薪水,查询除去最 ...
- 你知道ES6中的这些属性吗
ES6,也称ESMAScript2015,这个版本增加了很多好用的特性 变量声明 ES6之前用var来定义变量,ES6增加了两个变量声明的方式,分别为const和let,const用来定义常量,let ...
- DDD项目落地之充血模型实践
背景: 充血模型是DDD分层架构中实体设计的一种方案,可以使关注点聚焦于业务实现,可有效提升开发效率.提升可维护性: 1.DDD项目落地整体调用关系 调用关系图中的Entity为实体,从进入领域服务( ...