Как устранить утверждение среды выполнения Visual C++ «Блокировка была разрушена во время удержания»

В программе, которая использует DirectX для рендеринга 3D-компонента, я использую выделенный поток рендеринга, который, по-видимому, создается, если я вызываю DispatcherQueueController::CreateOnDedicatedThread(). То, что нужно отображать, зависит от действий, выполняемых в основном потоке, поэтому я использую scoped_lock для синхронизации доступа.

Код, создающий поток рендеринга, и код, работающий в нем, выглядят следующим образом:

      void MyCustomView::StartRenderingLoop()
{
  if(!_isRenderLoopRunning)
  {
    _renderLoopController = DispatcherQueueController::CreateOnDedicatedThread();
    _isRenderLoopRunning  = _renderLoopController.DispatcherQueue().TryEnqueue([this]()
    {
      while(_isRenderLoopRunning)
      {
        Concurrency::critical_section::scoped_lock lock(_criticalSection);

        if(_renderer->Render())
        {
          Present();
        }

        // Halt the thread until the next vblank is reached.
        // This ensures the app isn't updating and rendering faster than the display can refresh,
        // which would unnecessarily spend extra CPU and GPU resources. This helps improve battery life.
        _dxgiOutput->WaitForVBlank();
      }
    });
  }
}

Связанные переменные-члены в заголовочном файле C++ выглядят следующим образом:

      private:
  concurrency::critical_section _criticalSection;
  winrt::Microsoft::UI::Dispatching::DispatcherQueueController _renderLoopController{ nullptr };
  bool _isRenderLoopRunning  = false;

Чтобы остановить поток рендеринга, деструктор 3D-компонента содержит следующий код:

      MyCustomView::~MyCustomView()
{
  _isRenderLoopRunning = false;
  _renderLoopController.ShutdownQueueAsync();
}

Когда трехмерный компонент уничтожается, среда выполнения Visual C++ выдает утверждение, которое выглядит следующим образом:

      Debug Assertion Failed!

Program: MyAppPackage\CONCRT140D.dll
File: d:\agent\_work\18\s\src\vctools\crt\crtw32\concrt\rtlocks.cpp
Line: 1001

Expression: Lock was destructed while held

Стек вызовов, который я могу получить, выглядит следующим образом:

      concrt140d.dll!Concurrency::critical_section::~critical_section() + 79 bytes    Unknown
MyCustomComponents.dll!winrt::MyCustomComponents::implementation::BaseView::~BaseView() C++
MyCustomComponents.dll!winrt::implements<winrt::MyCustomComponents::implementation::MyCustomView,winrt::MyCustomComponents::MyCustomView,winrt::MyCustomComponents::implementation::BaseView,winrt::no_module_lock>::~implements<winrt::MyCustomComponents::implementation::MyCustomView,winrt::MyCustomComponents::MyCustomView,winrt::MyCustomComponents::implementation::BaseView,winrt::no_module_lock>()   C++
MyCustomComponents.dll!winrt::MyCustomComponents::implementation::MyCustomView_base<winrt::MyCustomComponents::implementation::MyCustomView,winrt::MyCustomComponents::implementation::BaseView>::~MyCustomView_base<winrt::MyCustomComponents::implementation::MyCustomView,winrt::MyCustomComponents::implementation::BaseView>() C++
MyCustomComponents.dll!winrt::MyCustomComponents::implementation::MyCustomView::~MyCustomView() Line 32 C++

Я изо всех сил пытаюсь понять, является ли утверждение Lock was destructed while heldуказывает на реальную проблему или на то, безопасно ли ее игнорировать. Если это реальная проблема, как мне ее правильно решить?

1 ответ

Мне кажется, проблема в том, что ваш основной поток уничтожает ваши объекты, которые содержат другой поток.

Вы пытаетесь решить эту проблему, установив для _isRenderLoopRunning значение false, но другие протекторы не будут синхронизированы с этим новым значением. Таким образом, другой поток продолжает работать, пока вы уничтожаете объект с помощью основного потока, что дает вам эту ошибку.

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

Другие вопросы по тегам