Простая синхронизация потоков - PullRequest
7 голосов
/ 11 марта 2009

Мне нужна простая блокировка «по одному» для фрагмента кода. Рассмотрим функцию func, которая может быть запущена из нескольких потоков:

void func()
{
     // locking/mutex statement goes here
     operation1();
     operation2();
     // corresponding unlock goes here
     operation3();
}

Мне нужно убедиться, что operation1 и operation2 всегда работают "вместе". С C # я бы использовал простой блок lock вокруг этих двух вызовов. Что такое эквивалент C ++ / Win32 / MFC?

Предположительно, какой-то Mutex?

Ответы [ 5 ]

27 голосов
/ 11 марта 2009

Исправление Решение Майкла и выше.

Решение Michael идеально подходит для приложений на Си. Но при использовании в C ++ этот стиль не рекомендуется из-за возможности исключений. Если исключение происходит в операции 1 или операции 2, критическая секция не будет правильно оставлена, и все другие потоки будут блокировать ожидание.

// Perfect solutiuon for C applications
void func()
{
    // cs previously initialized via InitializeCriticalSection
    EnterCriticalSection(&cs);
    operation1();
    operation2();
    LeaveCriticalSection(&cs);
    operation3();}
}

// A better solution for C++
class Locker
{
    public:
    Locker(CSType& cs): m_cs(cs)
    {
        EnterCriticalSection(&m_cs);
    }
    ~Locker()
    {
        LeaveCriticalSection(&m_cs);
    }
    private:
        CSType&  m_cs;
}
void func()
{
    // cs previously initialized via InitializeCriticalSection
    {
        Locker  lock(cs);
        operation1();
        operation2();
    }
    operation3();
}
19 голосов
/ 11 марта 2009

Критические секции будут работать (они легче, чем мьютексы). InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection и DeleteCriticalSection - это функции, которые нужно искать на MSDN .

void func()
{
    // cs previously initialized via InitializeCriticalSection
    EnterCriticalSection(&cs);
    operation1();
    operation2();
    LeaveCriticalSection(&cs);
    operation3();}
}

EDIT: Критические секции работают быстрее, чем мьютексы, так как критические секции в основном являются примитивами пользовательского режима - в случае несанкционированного получения (обычно в общем случае) системный вызов в ядре отсутствует, и получение занимает порядок десятков циклов. Переключатель ядра более дорогой (порядка сотен циклов). Единственный критический по времени раздел, обращающийся к ядру, предназначен для блокировки, что включает ожидание примитива ядра (мьютекс или событие). Получение мьютекса всегда включает вызов в ядро ​​и, следовательно, на несколько порядков медленнее. Однако критические секции могут использоваться только для синхронизации ресурсов в одном процессе. Для синхронизации между несколькими процессами необходим мьютекс.

6 голосов
/ 11 марта 2009
  1. с использованием MFC:

    1. Определить объект синхронизации. (Mutext или критический раздел)

      1.1 Если несколько потоков, принадлежащих разным процессам, входят в func (), затем используйте CMutex.

      1.2. Если в func () входит несколько потоков одного процесса, используйте CCriticalSection.

    2. CSingleLock можно использовать для упрощения использования объектов синхронизации.

Допустим, мы определили критическую секцию

 CCriticalSection m_CriticalSection;
    void func()
    {
         // locking/mutex statement goes here
         CSingleLock aLock(&m_CriticalSection, **TRUE**); 
       // TRUE indicates that Lock aquired during aLock creation.
       // if FALSE used then use aLock.Lock() for locking.

         operation1();
         operation2();
          // corresponding unlock goes here
          aLock.Unlock();
         operation3();
    }

РЕДАКТИРОВАТЬ: См. Статью VC ++ от MSDN: Многопоточность с классами C ++ и MFC и Многопоточность: как использовать классы синхронизации

6 голосов
/ 11 марта 2009

Лучший способ - использовать критический раздел, использовать EnterCriticalSection и LeaveCriticalSection. Единственное, что нужно, - это сначала инициализировать критический раздел с помощью InitializeCriticalSection. Если этот код находится внутри класса, поместите инициализацию в конструктор и структуру данных CRITICAL_SECTION в качестве члена класса. Если код не является частью класса, вам, вероятно, нужно использовать глобальный или что-то подобное, чтобы гарантировать его инициализацию один раз.

2 голосов
/ 11 марта 2009

Вы можете попробовать это:

void func()
{
    // See answer by Sasha on how to create the mutex
    WaitForSingleObject (mutex, INFINITE);
    operation1();
    operation2();
    ReleaseMutex(mutex);
    operation3();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...