C++ pthread的Win32替代方案
是否可以使用标准的win32 CreateMutex样式代码编写此代码。我只是想知道我是否想在我们的应用程序中引入一个新的库,或者我是否能找到一种自己编写这个库的方法。我就是不知道如何在关键区域内等待。这是我当前使用pthread库的工作代码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
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—只需确保您对其进行了适当的测试,并至少对返回值进行了一些验证