Приложение MFC зависло после вызова co_await BluetoothLEDevice:: FromIdAsync.

avatar
Hari
1 июля 2021 в 17:38
52
0
0

У меня есть одно приложение MFC, которое использует BLE DLL. Библиотека BLE позаботится о сканировании устройства, подключении и т. д.

Я попытался динамически связать BLE DLL. Сканирование устройства Bluetooth завершается без каких-либо проблем. Когда я попытался вызвать API ConnectToDevice из BLE DLL, возникла проблема.

API работает в других платформах C++, кроме MFC. Я только что создал диалоговое базовое приложение MFC и вызываю API библиотеки BLE из простого события нажатия кнопки.

Это пример кода

 fire_and_forget SensorDeviceInfo::ConnectToDevice(condition_variable& signal, bool& bConnected)
 {

     // Returns a BluetoothLEDevice object for the given Id and initiate a connection
     m_BluetoothLEDevice = co_await BluetoothLEDevice::FromIdAsync(GetId());
    
     if (m_BluetoothLEDevice == nullptr)
     {
         LogError(m_Log, __func__, "Failed to connect to device.");
     }

     if (m_BluetoothLEDevice != nullptr)
     {
        m_ConnectionStatusEventToken = m_BluetoothLEDevice.ConnectionStatusChanged({ this, 
                &SensorDeviceInfo::ConnectionStatusChangeHandler });
     }

   signal.notify_one();
}

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

            mutex mtxConnect;
            unique_lock lockConnect(mtxConnect);
            condition_variable cvConnect;

            // Connect to the sensor ble device
            m_CurrentDevice->ConnectToDevice(cvConnect, bConnected);
            cvConnect.wait(lockConnect);

Во время отладки приложения вызов поступает в место FromIdAsync, но через некоторое время он зависает, и стек вызовов исчезает.

Я использую VS2019 и последний распространяемый пакет (2019).

При проверке инструмента "Зависимости" я обнаружил, что в папке Windows\System32 отсутствуют некоторые библиотеки DLL.
Отсутствующие библиотеки DLL: api-ms-win-core-wow64-l1-1-0.dll, api-ms-win-core-wow64-l1-1-1.dll, api-ms-win-core -winrt-string-l1-1-0.dll. Здесь api-ms-win-core-wow64-l1-1-0.dll, api-ms-win-core-winrt-string-l1-1-0.dll доступны в других местах Windows. Но DLL api-ms-win-core-wow64-l1-1-1.dll отсутствует в системе.

Ниже приведены проблемы с зависимостями, заданные инструментом Зависимости

Dependencies

Я проверил mfc140.dll с машины другого коллеги. Проблема зависимости присутствует и на их машинах.

Я не знаю, является ли эта проблема с отсутствующей DLL основной причиной нашего библиотечного API ConnectToDevice.

Источник
IInspectable
2 июля 2021 в 12:45
1

Это неудобный код по многим причинам. Он запускает асинхронную задачу, а затем решает дождаться завершения синхронно. Синхронизация тоже избыточна. Я имею в виду, что если вы do хотите выполнить ConnectToDevice синхронно, просто верните ему IAsyncAction и вызовите для него функцию расширения C++/WinRT get(). Хотя, на самом деле, вы, конечно же, никогда не захотите блокировать поток пользовательского интерфейса.

IInspectable
2 июля 2021 в 12:47
1

Кроме того, передача ссылок в сопрограммы — это всегда ошибка, которая просто ждет своего часа.

Hari
3 июля 2021 в 16:05
0

Да вы правы. Я пробовал так же, как вы сказали. Я пробовал IAsyncAction и IAsyncOperation. Теперь API работают, и теперь я также могу заблокировать рабочий поток. Большое спасибо.

Hari
5 июля 2021 в 08:10
0

Проблема все еще возникает в моем исходном приложении MFC. В образце приложения MFC он работал без проблем.

IInspectable
5 июля 2021 в 10:41
1

Кажется, я припоминаю, что API BLE несколько привередлив, когда дело доходит до того, какой поток выполняет какой вызов. Хотя можно разгрузить вызов FromIdAsync в поток пула потоков, вы должны вернуться к исходному потоку до установки обратного вызова события. Второй пример в этом разделе объясняет, как вернуться к вызывающему потоку.

Hari
5 июля 2021 в 17:37
0

Поскольку мне нечего отображать в потоке пользовательского интерфейса, я использую сценарий разгрузки. co_await winrt::resume_background(); Приведенный выше код фактически решил мою проблему. Спасибо за немедленную помощь.

IInspectable
6 июля 2021 в 07:42
1

Я настроен скептически, но если у вас нет причин делать ConnectToDevice асинхронным, то просто не делайте этого. Превратите его в обычную функцию и замените оператор co_await на FromIdAsync(GetId()).get(). Нет никаких других точек приостановки, с которыми нужно иметь дело, и после этого изменения все просто работает в одном потоке. Хотя вы, вероятно, делаете асинхронную реализацию, чтобы не замораживать пользовательский интерфейс.

Hari
6 июля 2021 в 09:03
0

О Боже! Почему я не подумал об этом раньше. Спасибо @IInspectable за все ценные комментарии. Я просто удалил co_await и просто использовал .get() с самим WinRT API.

Ответы (0)