pthread 的 Win32 替代方案

Posted

技术标签:

【中文标题】pthread 的 Win32 替代方案【英文标题】:Win32 alternative to pthread 【发布时间】:2014-01-21 06:48:32 【问题描述】:

是否可以使用标准的 win32 CreateMutex 样式代码编写此代码。我只是想知道我是否想在我们的应用程序中引入一个新库,或者我是否可以找到一种自己编写的方法。我只是不知道如何在关键部分中等待。这是我当前使用 pthread 库的工作代码。

T remove() 
    pthread_mutex_lock(&m_mutex);
    while (m_queue.size() == 0) 
        pthread_cond_wait(&m_condv, &m_mutex);
    
    T item = m_queue.front();
    m_queue.pop_front();
    pthread_mutex_unlock(&m_mutex);
    return item;

【问题讨论】:

老实说,我会使用 C++11 中的 thread support library,VC++2012 及更高版本支持。如果您必须自己动手,那么诚实地使用 Windows 原语执行此操作是不值得的。如果您可以将您的安装域限制为 Vista/Server2008 及更高版本,则可以使用Windows Condition Variables,使其更加直接。 仔细考虑 WhozCraig 的建议。在 pre-Vista Win32 上滚动您自己的条件变量支持并非易事:cs.wustl.edu/~schmidt/win32-cv-1.html 我坚持支持 MSVC 6.0 和 MSVC 2010,所以它不是一个选项。但是,我可以使用 pthread 库,但想确保我没有错过一些简单的替代方案。我不是你的cmets。 风格说明:避免使用size() == 0 测试空虚;并非所有容器都提供 O(1) size(),这就是为什么有 empty() - 它不 [总是] 只是一个捷径。另外,在我看到您不能使用 C++11 之前,我将您的代码转换为 std::thread,请参见此处:pastebin.com/aVzJL1ag 【参考方案1】:

对于 VC-2012 之前的支持,最好的替代方案是支持条件变量的 Boost.Thread。

【讨论】:

我想是时候学习 Boost 了……但也许以后……再加上 Boost.Thread 仍然是一个额外的 dll,这是我试图避免的。 在您要求它存在之前,它不在附加 dll 中。默认情况下(至少在 Windows 上)它被编译为静态库。是的,它仍然应该编译,但这需要 5 分钟。 好的,谢谢。不知道那个。真的要找时间驯服Boost兽了……【参考方案2】:

这是我的尝试。这不是 win32 中条件等待锁的最佳实现,但我认为它有效。它可以使用仔细的代码审查审查。

一个警告 - 它不一定保证有序的公平性,因为所有等待的线程最初可能会被阻塞以等待事件。此时调度程序将恢复所有线程以继续运行(直到随后的阻塞 EnterCriticalSection 调用),但不一定按照线程到达 remove() 调用开始时的相同顺序。对于大多数只有少数线程的应用来说,这可能没什么大不了的,但这是大多数线程框架所保证的。

其他警告 - 为简洁起见,我省略了检查所有这些 Win32 API 的返回值的重要步骤。

CRITICAL_SECTION m_cs;
HANDLE m_event;

void Init()

   InitializeCriticalSection(&m_cs);
   m_event = CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset event


void UnInit()

    DeleteCriticalSection(&m_cs);
    CloseHandle(m_event);
    m_event = NULL;


T remove()

    T item;
    bool fGotItem = false;
    while (fGotItem == false)
    
        // wait for event to be signaled
        WaitForSingleObject(m_event, INFINITE);

        // wait for mutex to become available
        EnterCriticalSection(&m_cs);

        // inside critical section
        
            // try to deque something - it’s possible that the queue is empty because another 
            // thread pre-empted us and got the last item in the queue before us

            size_t queue_size = m_queue.size();

            if (queue_size == 1)
            
               // the queue is about to go empty
               ResetEvent(m_event);
            

            if (queue_size > 0)
            
                fGotItem = true;
                item = m_queue.front();

                m_queue.pop();        
            
        

        LeaveCriticalSection(&m_cs);

    

    return item;


void Add(T& item)

    // wait for critical section to become available
    EnterCriticalSection(&m_cs);

    // inside critical section
    
        m_queue.push_back(item);

        SetEvent(m_event); // signal other threads that something is available
    

    LeaveCriticalSection(&m_cs);

【讨论】:

谢谢,这对我来说是最好的答案。适用于 MSVC6.0 和 2012、Win7 和 WinXp! @uncletall - 只要确保您对其进行了适当的测试,并至少对 Init 和 WaitForSingleObject 调用中的调用的返回值进行一些验证。我实际上并没有编译或测试这段代码。我实际上是用我的 Mac-Mini 上的文本编辑器编写的 :)【参考方案3】:

Windows Vista 为此类场景引入了新的原生 Win32 Conditional Variable 和 Slim Reader/Writer Lock 原语,例如:

使用临界区:

CRITICAL_SECTION m_cs;
CONDITION_VARIABLE m_condv;

InitializeCriticalSection(&m_cs);
InitializeConditionVariable(&m_condv);

...

void add(T item)
 
    EnterCriticalSection(&m_cs);
    m_queue.push_back(item);
    LeaveCriticalSection(&m_cs);
    WakeConditionVariable(&m_condv);


T remove()
 
    EnterCriticalSection(&m_cs);
    while (m_queue.size() == 0)
        SleepConditionVariableCS(&m_condv, &m_cs, INFINITE);
    T item = m_queue.front();
    m_queue.pop_front();
    LeaveCriticalSection(&m_cs);
    return item;

使用 SRW 锁:

SRWLOCK m_lock;
CONDITION_VARIABLE m_condv;

InitializeSRWLock(&m_lock);
InitializeConditionVariable(&m_condv);

...

void add(T item)
 
    AcquireSRWLockExclusive(&m_lock);
    m_queue.push_back(item);
    ReleaseSRWLockExclusive(&m_lock);
    WakeConditionVariable(&m_condv);


T remove()
 
    AcquireSRWLockExclusive(&m_lock);
    while (m_queue.size() == 0)
        SleepConditionVariableSRW(&m_condv, &m_lock, INFINITE, 0);
    T item = m_queue.front();
    m_queue.pop_front();
    ReleaseSRWLockExclusive(&m_lock);
    return item;

【讨论】:

除非 OP 需要 WinXP 支持,否则我会赞成这个答案而不是我提供的答案。我忘记了 SRW 的东西。好答案!

以上是关于pthread 的 Win32 替代方案的主要内容,如果未能解决你的问题,请参考以下文章

pthread锁之pthread_mutexattr_t

有人用过Posix pthread win32库,dll文件

安装 pthread win32

为啥 MinGW 中仍然没有 std::thread、std::promise 和 std::future? win32中promise和futures的替代方案是啥?

C++ 11 替代 pthread_cond_timedwait

12.7 Cancal选项