C++ pthread的Win32替代方案

C++ pthread的Win32替代方案,c++,winapi,pthreads,win32-process,C++,Winapi,Pthreads,Win32 Process,是否可以使用标准的win32 CreateMutex样式代码编写此代码。我只是想知道我是否想在我们的应用程序中引入一个新的库,或者我是否能找到一种自己编写这个库的方法。我就是不知道如何在关键区域内等待。这是我当前使用pthread库的工作代码 T remove() { pthread_mutex_lock(&m_mutex); while (m_queue.size() == 0) { pthread_cond_wait(&m_condv, &am

是否可以使用标准的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;
}

这是我的尝试。这不是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);
}

这是我的尝试。这不是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);
}

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

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

Windows Vista为这种类型的场景引入了新的本机Win32和原语,例如:

使用临界截面:

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;
}

Windows Vista为这种类型的场景引入了新的本机Win32和原语,例如:

使用临界截面:

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;
}


老实说,我会使用VC++2012及更高版本支持的C++11中的。如果您必须自己使用Windows原语,那么诚实地使用Windows原语是不值得的。如果您可以将安装域限制为Vista /Serv2008和以后,您可以使用它,使其更加直接。请仔细考虑WhozCraig的建议。在Vista之前的Win32上运行您自己的条件变量支持并不是一件简单的事情:我坚持支持MSVC 6.0和MSVC 2010,所以这不是一个选项。但是,我可以使用pthread库,但是我想确保我没有遗漏一些简单的替代方法。从你的评论中我不是。风格说明:避免使用
size()==0测试空性;并非所有容器都提供O(1)
size()
,这就是为什么会有一个
empty()
——它[并不总是]只是一个快捷方式。另外,在我看到您不能使用C++11之前,我将您的代码转换为std::thread,请参见:老实说,我会使用VC++2012及更高版本支持的from C++11。如果您必须自己使用Windows原语,那么诚实地使用Windows原语是不值得的。如果您可以将安装域限制为Vista /Serv2008和以后,您可以使用它,使其更加直接。请仔细考虑WhozCraig的建议。在Vista之前的Win32上运行您自己的条件变量支持并不是一件简单的事情:我坚持支持MSVC 6.0和MSVC 2010,所以这不是一个选项。但是,我可以使用pthread库,但是我想确保我没有遗漏一些简单的替代方法。从你的评论中我不是。风格说明:避免使用
size()==0测试空性;并非所有容器都提供O(1)
size()
,这就是为什么会有一个
empty()
——它[并不总是]只是一个快捷方式。另外,在我看到您不能使用C++11之前,我将您的代码转换为std::thread,请参见:除非OP需要WinXP支持,否则我更喜欢这个答案,而不是我提供的答案。我已经忘了SRW的事了。回答得好!除非OP需要WinXP支持,否则我更喜欢这个答案。我已经忘了SRW的事了。回答得好!我想现在是我学习Boost的时候了。。。但也许以后。。。加上Boost.Thread仍然是一个额外的dll,这是我一直试图避免的。它不在额外的dll中,直到你要求它在那里。默认情况下(至少在Windows上),它被编译为静态库。是的,它仍然应该被编译,但这需要5分钟。好的,谢谢。我不知道。真的要找时间驯服助推野兽…我想是时候学习助推了。。。但也许以后。。。加上Boost.Thread仍然是一个额外的dll,这是我一直试图避免的。它不在额外的dll中,直到你要求它在那里。默认情况下(至少在Windows上),它被编译为静态库。是的,它仍然应该被编译,但这需要5分钟。好的,谢谢。我不知道。真的需要花点时间驯服这只猛兽…谢谢,这对我来说是最好的答案。适用于MSVC6.0和2012、Win7和WinXp@uncletall-只需确保对其进行适当的测试,并至少对Init和WaitForSingleObject调用中的返回值进行一些验证。我并没有编译或测试这段代码。事实上,我是用Mac Mini上的文本编辑器写的:)谢谢,这是我最好的答案。适用于MSVC6.0和2012、Win7和WinXp@uncletall—只需确保您对其进行了适当的测试,并至少对返回值进行了一些验证