一次性初始化

更新时间:
2024-05-13
下载文档

一次性初始化

有些情况,我们需要对一些 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
文档内容是否对您有所帮助?
有帮助
没帮助