使用函数之once

博客介绍了一个简单的单次执行函数,它在特殊业务中有实际用途,如点击付款按钮只需用户点击一次,再次点击无效。该函数简单实用,可封装成业务函数,节省不必要的代码。
var once = fn => {
   let done = false;
   return function(){
    return done?undefined:((done = true),fn.apply(this,arguments))
   }
 }

这是一个简单的执行一次的函数,在一些特殊的业务中有一定的实际用途,比如当我们想要点击付款按钮时,我们只需要用户点击一次,如果第二次再次点击则无效。

var doPayment = once(()=>{
       console.log(‘支付完成了’)
})
doPayment() //支付完成了

此时我们不小心重复点击了第二次;

doPayment()  //undefined

这个函数简单实用,我们可以把它封装成我们自己的业务函数,这样会节省我们很多不必要的代码。

<think>嗯,用户想了解pthread_once函数的详细用法和功能。首先,我需要回忆这个函数的基本作用。根据之前的引用,pthread_once用于多线程环境下确保某个函数只执行一次。比如引用[1]提到,它通过once_control来控制初始化函数只被调用一次,即使在多个线程中被多次调用。接下来,用户可能想知道具体怎么使用这个函数。引用[2]中的例子显示,当创建了5个子线程,每个线程都调用pthread_once,但实际的初始化函数initialize_once只执行了一次。这说明once_control变量是关键,它必须是静态或全局的,保证所有线程看到相同的状态。然后,我需要解释函数原型,参数once_control和init_routine的作用。once_control的类型是pthread_once_t,必须初始化为PTHREAD_ONCE_INIT。init_routine是实际要执行的一次性函数。返回值的处理也很重要,成功返回0,错误返回错误码。用户可能还需要代码示例。根据引用中的例子,可以构造一个简单的例子,展示多个线程调用pthread_once,但初始化函数只执行一次。同时,需要注意线程的创建和同步,比如使用pthread_join来等待线程结束。 另外,用户可能关心这个函数的应用场景。比如,在数据库连接初始化、日志系统配置加载等需要线程安全的一次性初始化时使用。引用[4]提到互斥锁的清理,可能和资源管理有关,但pthread_once更多是初始化而非清理。还要注意与其他同步机制的区别,比如互斥锁和条件变量。引用[3]提到了pthread_cond_wait的复杂性,而pthread_once提供了一种更简洁的方式来处理一次性初始化,避免重复初始化的开销和竞争条件。 最后,生成相关问题需要考虑用户可能进一步的问题,比如错误处理、线程安全、与其他函数的配合使用,以及在不同系统下的行为差异。这些问题可以帮助用户深入理解pthread_once使用和限制。</think>### pthread_once函数详解 #### 一、核心功能 `pthread_once`是POSIX线程库提供的同步控制函数,用于**确保多线程环境下指定函数只执行一次**。其核心机制通过`pthread_once_t`控制变量实现,满足以下特性: - **原子性**:保证初始化函数仅被首个调用线程执行 - **可见性**:所有线程将看到初始化完成后的状态 - **线程安全性**:无需额外加锁操作[^1] #### 二、函数原型与参数 ```c #include <pthread.h> int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); ``` - **once_control**:控制变量,必须初始化为`PTHREAD_ONCE_INIT` $$ \text{pthread\_once\_t once\_control = PTHREAD\_ONCE\_INIT;} $$ - **init_routine**:一次性初始化函数指针 #### 三、典型应用场景 1. 线程安全的单例模式实现 2. 动态库的首次加载初始化 3. 共享资源的唯一性配置(如日志系统、数据库连接池) #### 四、代码示例 ```c #include <pthread.h> #include <stdio.h> pthread_once_t once_control = PTHREAD_ONCE_INIT; void initialize_once() { printf("Initialization by thread %lu\n", pthread_self()); } void* thread_func(void* arg) { pthread_once(&once_control, initialize_once); printf("Thread %lu continues\n", pthread_self()); return NULL; } int main() { pthread_t tid[5]; for (int i=0; i<5; ++i) pthread_create(&tid[i], NULL, thread_func, NULL); for (int i=0; i<5; ++i) pthread_join(tid[i], NULL); return 0; } ``` **输出示例**: ``` Initialization by thread 140737297565440 Thread 140737297565440 continues Thread 140737288172736 continues Thread 140737279780032 continues Thread 140737271387328 continues Thread 140737262994624 continues ``` #### 五、实现原理 1. 通过原子操作检查控制变量状态 2. 首个调用线程执行初始化函数并更新状态 3. 后续线程直接跳过初始化过程[^2] #### 六、注意事项 1. 控制变量必须为全局或静态变量 2. 初始化函数不应抛出异常(C++需特别处理) 3. 与互斥锁配合使用时注意执行顺序[^3][^4] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值