一次性初始化
有些情况,我们需要对一些 POSIX 对象只进行一次性初始化,如线程键 pthread_key_t。如果我们进行多次初始化就会出现错误。
在传统的顺序编程中,一次性初始化经常通过使用布尔 BOOL 类型的变量来管理。布尔类型的控制变量被静态初始化为 FALSE,而任何依赖于初始化的代码都能测试该变量。如果变量的值为 FALSE,则实行初始化,将变量的值设置为 TRUE。以后检查的代码将跳过初始化。
但是在多线程程序中,事情就变得复杂了。如果多个线程并发地执行初始化序列代码,可能有多个线程同时发现变量的值为 FALSE,并且都实行初始化,而该过程本该仅仅执行一次。
虽然我们可以加入一个 POSIX 互斥信号量保护初始化过程不被多次执行,但是使用 POSIX 标准提供的 pthread_once_t 变量和 pthread_once 函数会方便的多。
pthread_once_t 变量的定义与初始化:
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once_t 变量
#include <pthread.h>
int pthread_once(pthread_once_t *once, void (*pfunc)(void));
函数 pthread_once 原型分析:
- 此函数返回错误号 ERRNO_NONE 或 POSIX 标准错误号(errno 记录了出错原因)。
- 参数 once 是 pthread_once_t 类型变量的指针。
- 参数 pfunc 是完成一次性初始化的函数指针。
SylixOS 同样提供了一个类似于 pthread_once 函数的 API:
#include <SylixOS.h>
INT Lw_Thread_Once(BOOL *pbOnce, VOIDFUNCPTR pfuncRoutine);
函数 Lw_Thread_Once 原型分析:
- 此函数返回错误号。
- 参数 pbOnce 是布尔 BOOL 类型变量的指针。
- 参数 pfuncRoutine 是完成一次性初始化的函数指针。
下面程序展示了 pthread_once_t 变量和 pthread_once 函数的使用,该程序修改自程序清单 POSIX条件变量的使用(POSIX_Conditional_Variable),将 POSIX 条件变量和 POSIX 互斥量的创建放置在一次性初始化的函数中,虽然 pthread_once(&once, var_init)语句被调用两次,但 var_init 函数只会被调用一次。
#include <stdio.h>
#include <pthread.h>
static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_mutex_t lock;
static pthread_cond_t cond;
static int count = 0;
static void var_init(void)
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
}
static void *thread_a (void *arg)
{
pthread_once(&once, var_init);
while (1) {
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
printf("thread_a(): count = %d\n", count);
pthread_mutex_unlock(&lock);
}
return (NULL);
}
static void *thread_b (void *arg)
{
pthread_once(&once, var_init);
while (1) {
pthread_mutex_lock(&lock);
count++;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
sleep(1);
}
return (NULL);
}
int main (int argc, char *argv[])
{
pthread_t threada_tid;
pthread_t threadb_tid;
int ret;
ret = pthread_create(&threada_tid, NULL, thread_a, NULL);
if (ret != 0) {
fprintf(stderr, "pthread create failed.\n");
return (-1);
}
ret = pthread_create(&threadb_tid, NULL, thread_b, NULL);
if (ret != 0) {
fprintf(stderr, "pthread create failed.\n");
return (-1);
}
pthread_join(threada_tid, NULL);
pthread_join(threadb_tid, NULL);
return 0;
}
在 SylixOS Shell 下运行程序:
# ./ Function_pthread_once
thread_a(): count = 1
thread_a(): count = 2
thread_a(): count = 3
thread_a(): count = 4
thread_a(): count = 5
thread_a(): count = 6
......
# ts
NAME TID PID PRI STAT LOCK SAFE DELAY PAGEFAILS FPU CPU
--------------------- ------- ----- --- ---- ---- ---- ---------- --------- --- ---
Function_pthread_once 4010095 46 200 JOIN 0 0 1 USE 0
pthread 4010096 46 200 SEM 0 0 0 0
pthread 4010097 46 200 SLP 0 521 0 0