4

你好。我正在尝试为我的库创建一个完全线程安全的初始化函数,但我无法轻易找到 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()调用导致一个线程不安全的函数,该函数初始化库。

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

4

5 回答 5

7

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

这里有示例代码

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

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
}
于 2009-03-11T02:31:03.530 回答
3

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

于 2009-03-22T16:58:50.823 回答
2

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

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()来替换我的代码中一些相当复杂的函数。

于 2009-03-11T02:15:27.450 回答
2

使用 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");
}
于 2011-04-12T17:55:58.913 回答
0

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

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

于 2009-03-10T22:19:24.680 回答