【问题标题】:Library initialization -- pthread_once in Win32 implementation库初始化——Win32实现中的pthread_once
【发布时间】:2009-03-10 19:24:43
【问题描述】:

你好。我正在尝试为我的库创建一个完全线程安全的初始化函数,但我无法轻易找到 pthread_once 的替代方法,它应该很容易解决问题。我来到了这段代码:


void libInit (void)
{
#ifdef WIN32
    static volatile int initialized = 0;
    static HANDLE mtx;

    if (!initialized)
    {
        if (!mtx)
        {
            HANDLE mymtx;
            mymtx = CreateMutex(NULL, 0, NULL);
            if (InterlockedCompareExchangePointer(&mtx, mymtx, NULL) != NULL)
                CloseHandle(mymtx);
        }

        WaitForSingleObject(mtx);
        if (!initialized)
        {
            libInitInternal();
            initialized = 1;
        }
        ReleaseMutex(mtx);
    }
#else
    static pthread_once_t initialized = PTHREAD_ONCE_INIT;

    pthread_once(&initialized, libInitInternal);
#endif
}

libInitInternal() 调用会导致线程不安全函数,该函数会初始化库。

我想听听关于我可能做错了什么或您是否知道更好的解决方案的任何建议。

【问题讨论】:

  • 这是静态库还是 dll?
  • 它不是 DLL。我知道 DLL 有一个初始化函数,但这不是我想要的。

标签: c winapi initialization


【解决方案1】:

我认为您想使用One-Time Initialization 功能。在同步模式下,所有线程都会阻塞,直到第一个调用它的线程完成。似乎类似于 pthread_once()。

sample code here

所以在你的情况下,你会说:

BOOL CALLBACK CallLibInitInternal(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) {
    libInitInternal();
    return TRUE;
}

void libInit() {
#ifdef WIN32
    static INIT_ONCE s_init_once;
    InitOnceExecuteOnce(&s_init_once, CallLibInitInternal, NULL, NULL);
#else
...
#endif
}

【讨论】:

  • 这只能在 Windows Vista 和更新版本上使用。我很想有一些可以在 Windows 98 上运行的东西。
  • 真的吗?我在文档中完全错过了这一点。对不起。您需要编写代码并且您的 OP 看起来很接近。可能想要创建一个每个人都在等待的命名对象,以便他们都在等待同一个对象。
【解决方案2】:

您可能想检查pthreads-win32 在其pthread_once() 实现中的作用。或者只是使用它,如果这被证明更容易的话。

【讨论】:

    【解决方案3】:

    在查看了以下 pthread_once() 的源代码(来自here)之后,看来您走在了正确的轨道上。

    int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { /* 首先检查速度 */ if (once_control->state == PTHREAD_NEEDS_INIT) { pthread_mutex_lock(&(once_control->mutex)); if (once_control->state == PTHREAD_NEEDS_INIT) { 初始化例程(); 一次控制->状态= PTHREAD_DONE_INIT; } pthread_mutex_unlock(&(once_control->mutex)); } 返回(确定); }

    顺便说一句,我将使用 pthread_once() 来替换我的代码中一些相当复杂的函数。

    【讨论】:

    • 不是双重检查锁定反模式吗?它应该不能便携式工作。如果没有在我的平台上/在编写它的平台之外进行密集测试,我不会使用它...请参阅 S. Meyers 和 A. Alexandrescu 的以下文章:aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
    【解决方案4】:

    使用 GCC 或 clang 时,可以使用构造函数和析构函数属性。它们适用于共享库和静态库,并分别在 main 运行之前和之后执行代码。此外,您可以指定多个构造函数和析构函数。比单例方法干净得多,并且不需要您记住从 main() 调用 libInit()。

    static void __attribute__((constructor))
    your_lib_init(void)
    {
        fprintf(stderr, "library init\n");
    }
    
    static void __attribute__((destructor))
    vensim_ctx_destroy(void)
    {
        fprintf(stderr, "library destroy\n");
    }
    

    【讨论】:

    • 这是非标准的,所以我想它必须由其他编译器的常规“单例方法”来支持。不过,它确实看起来不错。如果可以,我会 +1。
    【解决方案5】:

    我会看看这篇文章。这是针对 C++ 单例的解决方案,但我相信您也可以在代码中使用该解决方案:http://www.ddj.com/cpp/199203083?pgno=1

    遗憾的是,QLock 本身的清单丢失了,看起来他们好像在试图出售 CD,但似乎有足够的描述来自己写一张。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 2015-09-10
      • 2011-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-26
      相关资源
      最近更新 更多