Можно ли написать это, используя стандартный код стиля win32 CreateMutex. Мне просто интересно, хочу ли я добавить новую библиотеку в наше приложение или я могу найти способ написать это сам. Я просто не могу понять, как ждать внутри CriticalSection. Это мой текущий рабочий код с библиотекой 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);
}
Для поддержки до VC-2012 лучшая альтернатива Boost.Thread который поддерживает условные переменные.
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;
}