Win32 альтернатива pthread

Можно ли написать это, используя стандартный код стиля 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;
}

3 ответа

Решение

Вот моя попытка. Это не лучшая реализация условной блокировки ожидания в 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 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;
}
Другие вопросы по тегам