如何使用 win32 从多线程上下文初始化线程原语?

Posted

技术标签:

【中文标题】如何使用 win32 从多线程上下文初始化线程原语?【英文标题】:How do I initialize thread primitives from a multithreaded context with win32? 【发布时间】:2014-01-15 07:41:50 【问题描述】:

我想创建一个静态锁

void foo()
    static CRITICAL_SECTION *lock = NULL; //this is the problem, I cannot create any primitive to do this with win32 threads
    static long isInitialized = 0;
    if (InterlockedExchange(&isInitialized, 1) == 0) //this will ensure that lock is initialized only once
        lock = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
        InitializeCriticalSection(lock);
    
    EnterCriticalSection(lock); //this might be called before initialization is done...YIKES!
    ...
    LeaveCriticalSection(lock); 

如何从多线程上下文初始化锁?

一个糟糕的解决方案可能如下所示:

void foo()
    static CRITICAL_SECTION *lock = NULL; //this is the problem, I cannot create any primitive to do this with win32 threads
    static long isInitialized = 0;
    static volatile long isInitializeDone = 0;
    if (InterlockedExchange(&isInitialized, 1) == 0) //this will ensure that lock is initialized only once
        lock = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
        InitializeCriticalSection(lock);
        isInitializeDone = 1;
     else 
        while (isInitializeDone == 0)

        
    
    EnterCriticalSection(lock); //this might be called before initialization is done...YIKES!
    ...
    LeaveCriticalSection(lock); 

但是有更好的解决方案吗?

【问题讨论】:

如果可能的话,通过在启动多个将使用该原语进行同步的线程之前初始化每个原语来避免该问题。 看看this question和one of its answers。 @xaizek 如果我不需要支持 windows xp 那就完美了 您意识到代码中没有为临界区分配任何内存?此外,您应该将指向临界区的指针传递给 InitializeCriticalSection,而不是指向指针的指针。 @HarryJohnston 是的,这是一个错字。不过修复它。 【参考方案1】:

如果这是 C++,您可以调用一个函数来初始化该临界区:

static CRITICAL_SECTION *lock = get_critical_section();

喜欢

CRITICAL_SECTION* get_critical_section()

    CRITICAL_SECTION *lock = NULL;
    InitializeCriticalSection(&lock);
    return lock;

C++ 指定只有一个线程会初始化那个东西,而所有其他线程都会等待它:

[stmt.dcl]

如果控制进入 在变量初始化的同时声明,并发执行应等待 初始化完成。 编辑:我不知道什么时候标准中的文本是这样的,但我很确定这是所有实现所做的。

【讨论】:

这是什么标准? c也是这样吗? 不,这仅适用于 C++,我的标准副本来自半年前。在C中,您不走运。可以下载最新的C++标准草案here【参考方案2】:

另一个选择是利用每个进程都有一个默认堆和一个已经初始化的关联锁这一事实:

void foo(void)

    static CRITICAL_SECTION lock;
    static DWORD lock_status = 0;

    if (lock_status == 0)
    
        HANDLE process_heap = GetProcessHeap();
        if (!HeapLock(process_heap)) fail();

        if (lock_status == 0)
        
            InitializeCriticalSection(&lock);
            lock_status = 1;
        

        if (!HeapUnlock(process_heap)) fail();
    
    EnterCriticalSection(&lock);
    // ...
    LeaveCriticalSection(&lock);

【讨论】:

以上是关于如何使用 win32 从多线程上下文初始化线程原语?的主要内容,如果未能解决你的问题,请参考以下文章

在 Win32/MFC 和 POSIX 中,线程会自行清理吗?

win32 api 原理

如何从 win32 进程获取线程句柄列表?

win32 相关同步api

win32 相关同步api

如何使用 AfxBeginThread创建MFC线程对象和Win32线程对象