Как сделать цикл потоков Win32 / MFC синхронным?

Я новичок в многопоточности в Windows, поэтому у меня может возникнуть тривиальный вопрос: какой самый простой способ убедиться, что потоки выполняют цикл синхронно?

Я попытался передать общий массив Event всем потокам и использовать WaitForMultipleObjects в конце цикла для их синхронизации, но это привело к тупиковой ситуации после одного, а иногда и двух циклов. . Вот упрощенная версия моего текущего кода (всего с двумя потоками, но я бы хотел сделать его масштабируемым):

typedef struct
{
    int rank;
    HANDLE* step_events;
} IterationParams;

int main(int argc, char **argv)
{
    // ...

    IterationParams p[2];
    HANDLE step_events[2];
    for (int j=0; j<2; ++j)
    {
        step_events[j] = CreateEvent(NULL, FALSE, FALSE, NULL);
    }

    for (int j=0; j<2; ++j)
    {
        p[j].rank = j;
        p[j].step_events = step_events;
        AfxBeginThread(Iteration, p+j);
    }

    // ...
}

UINT Iteration(LPVOID pParam)
{
    IterationParams* p = (IterationParams*)pParam;
    int rank = p->rank;

    for (int i=0; i<100; i++)
    {
        if (rank == 0)
        {
            printf("%dth iteration\n",i);
            // do something
            SetEvent(p->step_events[0]);
            WaitForMultipleObjects(2, p->step_events, TRUE, INFINITE);
        }
        else if (rank == 1)
        {
            // do something else
            SetEvent(p->step_events[1]);
            WaitForMultipleObjects(2, p->step_events, TRUE, INFINITE);
        }
    }
    return 0;
}

(Я знаю, что смешиваю C и C ++, на самом деле это унаследованный код C, который я пытаюсь распараллелить.)

Читая документацию в MSDN, думаю, это должно сработать. Однако поток 0 печатает только один раз, иногда дважды, а затем программа зависает. Это правильный способ синхронизации потоков? Если нет, что бы вы порекомендовали (действительно ли в MFC нет встроенной поддержки барьера?).


ИЗМЕНИТЬ : это решение НЕПРАВИЛЬНО , даже включая исправление Алессандро . Например, рассмотрим следующий сценарий:

  1. Поток 0 устанавливает свое событие и вызывает Wait, блоки
  2. Поток 1 устанавливает свое событие и вызывает Wait, блоки
  3. Поток 0 возвращается из Wait, сбрасывает свое событие и завершает цикл без получения управления потоком 1
  4. Поток 0 устанавливает собственное событие и вызывает ожидание. Поскольку у потока 1 еще не было возможности сбросить свое событие, ожидание потока 0 немедленно возвращается, и потоки выходят из синхронизации.

Таким образом, остается вопрос: как можно безопасно гарантировать, что потоки остаются в синхронизированном состоянии. ?

5
задан Community 23 May 2017 в 11:58
поделиться