Утверждение, что текущий поток не держит блокировку CRITICAL_SECTION - PullRequest
1 голос
/ 15 февраля 2012

У меня есть объект, который поддерживает список;один из вспомогательных методов должен

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

Операция очистки удаляет объект из списка из другогопоток, таким образом, он должен заблокировать список между ними.

Это работает нормально, если помощник не вызывается с блокировкой в ​​списке, которая уже удерживается, так как операция разблокировки фактически не позволит другому потокудоступ к списку, поэтому я хотел бы отметить ошибку в этом случае.

Насколько я понял, API CRITICAL_SECTION не предоставляет официально поддерживаемый способ запроса, удерживает ли текущий процессэтот объект, поэтому я рассматриваю подходы "взлома" (в конце концов, это средство отладки и не предназначено для ввода в производственный код):

Вариант 1 - проверка поля OwningThread поляCRITICAL_SECTION структура, но мне интересно, есть ли гарантия, что это поле

  • всегда содержит идентификатор потока из того же числа, что и GetCurrentThreadId() результаты
  • всегда обновляются при любомпоток получает блокировку
  • всегда очищается, когда мой собственный поток снимает блокировку

Вариант 2 заключается в блокировке CRITICAL_SECTION, а затем проверяет RecursionCount;это предполагает, что счетчик рекурсии имеет фиксированное начальное значение.

Есть ли что-то, что я пропустил, что я мог бы использовать для создания некоторого будущего (то есть, он будет шумно ломаться в строке кода, котораярядом с комментариями, где я все это объясняю) утверждение о том, что текущий поток не является держателем определенного CRITICAL_SECTION?

Ответы [ 2 ]

2 голосов
/ 15 февраля 2012

Создайте свой собственный критический раздел, который предоставляет такую ​​функцию. Используйте его в ваших отладочных сборках. В сборках выпуска используйте обычный критический раздел.

Один простой способ - использовать два критических раздела и поле владельца. Приобретение работает так:

  1. Получить первый критический участок.

  2. Получить второй критический участок.

  3. Установить владельца этой темы.

  4. Отпустить вторую критическую секцию.

Релиз работает так:

  1. Получить второй критический участок.

  2. Установить владельца нет.

  3. Отпустить первую критическую секцию.

  4. Отпустить вторую критическую секцию.

Assert работает так:

  1. Получить второй критический участок.

  2. Владелец утверждения не является этой темой.

  3. Отпустить вторую критическую секцию.

Обновление : в приведенном выше сообщении есть ошибка. Это неправильно обрабатывает этот случай: блокировка, блокировка, разблокировка, утверждение, что мы не держим критическую секцию, но делаем. Исправление, вероятно, заключается в том, чтобы сохранить «счетчик блокировок». Вам не нужно устанавливать CS в «unowned» со счетчиком блокировок. Если количество блокировок равно нулю, оно не используется. Таким образом, пути утверждений "не принадлежат или не принадлежат этому потоку".

1 голос
/ 23 апреля 2012

Я использую что-то подобное

class CriticalSection
{
private:
  CRITICAL_SECTION section_;
  unsigned int owning_thread_id_;
  unsigned int lock_count_;

public:
  CriticalSection() 
  {
    InitializeCriticalSection(&section_);
    owning_thread_id_ = 0;
    lock_count_ = 0;

  }
  ~CriticalSection()
  {
    DeleteCriticalSection(&section_);
  }

  void enter()
  {
    EnterCriticalSection(&section_);
    owning_thread_id_ = GetCurrentThreadId();
    lock_count_ ++;
  }
  void leave()
  {

    if(  GetCurrentThreadId() == owning_thread_id_ )
    {
      lock_count_ --;
      if( lock_count_ == 0 )
        owning_thread_id_ = 0;
    }

    LeaveCriticalSection(&section_);
  }

  bool tryEnter() 
  { 
    if( TryEnterCriticalSection(&section_))
    {
      owning_thread_id_ = GetCurrentThreadId();
      lock_count_ ++;
      return true;
    }
    return false;
  }

  bool isCurrentThreadEntered()
  {
    return GetCurrentThreadId() == owning_thread_id_;
  }

  int getLockCount() { return lock_count_; }
  unsigned int getOwningThreadID() { return owning_thread_id_; }

};
...