Как передать критический раздел в другой поток? - PullRequest
0 голосов
/ 29 марта 2020

У меня 3 потока, возобновленных одновременно, вызывающих одну и ту же функцию с разными аргументами. Как я могу заставить поток покинуть критическую секцию и передать его другому потоку?

Когда я запускаю приведенный ниже код, в то время как l oop вызывается много раз, пока не вступит другой поток критический раздел (и он также многократно повторяется).

DWORD WINAPI ClientThread(LPVOID lpParam)
{
    // thread logic 
    while(true)
    {
        EnterCriticalSection(&critical);
        // thread logic 
        LeaveCriticalSection(&critical);
        Sleep(0);
    }
    // thread logic 
    return 0;
}

Другими словами, как я могу предотвратить повторный повторный вход потока в раздел?

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Вы не можете напрямую просить ветку покинуть критический раздел. Поток покинет его, когда завершит выполнение.

Таким образом, единственный способ - предотвратить вход в критическую секцию или «попросить» его завершить sh рано. Например. непрерывно проверяя в секции atomic_flag и прерывая остановку работы потока, если он был проверен.

Если вы хотите запретить потоку повторно входить в раздел сразу после его выхода, вы можете получить его, это перенесет выполнение потоков. Если вам нужен точный порядок из потоков (A-> B -> C -> D-> A-> B ...), вам нужно написать собственный планировщик или пользовательский "fair_mutex", который обнаружит другие ожидающие потоки.

Редактировать:
Такая функция будет BOOL SwitchToThread(); do c

1 голос
/ 30 марта 2020

Как уже упоминалось в другом ответе, вам нужен Fair Mutex, и Ticket Lock может быть одним из способов его реализации.

Есть другой способ, основанный на двоичном семафоре, и он на самом деле близко к тому, что раньше было критическим разделом. Например:

class old_cs
{
public:
  old_cs()
  {
     event = CreateEvent(NULL, /* bManualReset = */ FALSE, /* bInitialState =*/ TRUE, NULL);
     if (event == NULL) throw std::runtime_error("out of resources");
  }

  ~old_cs()
  {
     CloseHandle(event);
  }

  void lock()
  {
    if (count.fetch_add(1, std::memory_order_acquire) > 0)
      WaitForSingleObject(event, INFINITE);
  }

  void unlock()
  {
    if (count.fetch_sub(1, std::memory_order_release) > 1)
      SetEvent(event);
  }

  old_cs(const old_cs&) = delete;
  old_cs(old_cs&&) = delete;
  old_cs& operator=(const old_cs&) = delete;
  old_cs& operator=(old_cs&&) = delete;
private:
  HANDLE event;
  std::atomic<std::size_t> count = 0;
};

В документации Объекты критических разделов можно найти следующее *1009*:

Начиная с Windows Server 2003 с пакетом обновления 1 ( SP1), потоки, ожидающие в критической секции, не получают критическую секцию в порядке поступления. Это изменение значительно повышает производительность для большей части кода. Однако некоторые приложения зависят от порядка «первым пришел - первым вышел» (FIFO) и могут работать плохо или не работать вообще в текущих версиях Windows (например, приложения, которые использовали критические секции в качестве ограничителя скорости). Чтобы ваш код продолжал работать правильно, вам может потребоваться добавить дополнительный уровень синхронизации. Например, предположим, что у вас есть поток производителя и поток потребителя, которые используют объект критического раздела для синхронизации своей работы. Создайте два объекта события, по одному для каждого потока, чтобы указать, что он готов для продолжения другого потока. Поток потребителя будет ждать, пока производитель сообщит о своем событии, прежде чем войти в критическую секцию, а поток производителя будет ждать, пока поток потребителя не сообщит о своем событии, прежде чем войти в критическую секцию. После того, как каждый поток покидает критический раздел, он сообщает о своем событии, чтобы освободить другой поток.

Таким образом, алгоритм в этом посте является упрощенной версией того, что раньше было в критическом разделе в Windows XP и более ранних версиях. .

Приведенный выше алгоритм не является полным критическим разделом, в нем отсутствуют поддержка рекурсии, вращение, обработка ситуаций с низким уровнем ресурсов.

Также он опирается на Windows Справедливость событий.

...