LIB_API ErrorCode getSensorValue(SensorNumber number, SensorValue* value);
LIB_API ErrorCode querySensorValue(SensorNumber number, SensorValueCallback callback, void* pContextData);
LIB_API ErrorCode readSensorValues(SensorValueCallback callback, void* pContextData);
LIB_API ErrorCode getMinValue(SensorNumber first, SensorNumber last, SensorValue* value);
LIB_API ErrorCode getMaxValue(SensorNumber first, SensorNumber last, SensorValue* value);
LIB_API ErrorCode setAlert(SensorNumber number, SensorAlertCallback callback, SensorValue alertValue, AlertRule alertRule, CheckAlertTimeout checkTimeoutSeс, void* pContextData);
LIB_API ErrorCode resetAlert(SensorNumber number);
LIB_API ErrorCode setSimulateReadCallback(OnSimulateReadValue callback, void* pContextData);
LIB_API ErrorCode setSimulateOperableCallback(OnSimulateOperable callback, void* pContextData);
В реализации этих функций мы будем возвращать код ошибки, получая его из перехваченного исключения. В качестве примера рассмотрим реализацию функции для получения значения датчика (Листинг 105).
Листинг 105. Функция для получения значения датчика
ErrorCode getSensorValue(SensorNumber number, SensorValue* value)
{
ErrorCode error = ERROR_NO; // (1)
try
{
*value = g_SensorControl->getSensorValue(number); // (2)
}
catch (sensor::sensor_exception& e) // (3)
{
error = e.code(); // (4)
}
return error; // (5)
}
В строке 1 объявляем переменную – код возврата. В строке 2 осуществляем вызов метода класса, который заключен в блок try. В строке 3 осуществляется перехват исключения, в строке 4 присваивается код ошибки, который возвращается в строке 5.
Итак, мы придумали, как в интерфейсных функциях осуществлять обработку ошибок. Теперь перед нами встает следующая проблема: как настраивать типы драйверов, ведь в исходной реализации для этого используются классы? Прежде чем перейти к решению этой задачи, остановимся на реализации многопоточной работы, поскольку используемые там конструкции нам понадобятся в дальнейшем.
6.3.4. Многопоточная работа
В исходной реализации в каждом потоке мы могли создать свой экземпляр класса ISensorControlи работать с ним независимо. В случае API это не работает, потому что экземпляр класса в реализации интерфейса объявляется глобальным, и все интерфейсные функции обращаются к одному и тому же экземпляру класса. Выходом здесь будет выделение отдельной области памяти для экземпляра класса в рамках одного потока, т. е. использование локальной памяти потока.
До появления стандарта C++ 11 использовать локальную память потока было непросто: для этого требовалось явное обращение к функциям операционной системы, что усложняло реализацию и делало код платформенно-зависимым. В C++ 11 появилось ключевое слово thread_local, и это сильно упростило жизнь: если в объявлении переменной добавить указанный спецификатор, то она становится локальной в рамках потока, т. е. каждый новый создаваемый поток будет иметь независимый экземпляр соответствующей переменной. Таким образом, достаточно экземпляр интерфейсного класса ISensorControlобъявить как thread_local, и теперь для каждого потока будет существовать отдельный независимый экземпляр класса (Листинг 106).
Листинг 106. Объявление экземпляра класса как локального для текущего выполняемого потока (SensorLib.cpp)
using ControlPointer = std::unique_ptr;
thread_local ControlPointer g_SensorControl(sensor::ISensorControl::createControl());
6.3.5. Настройка драйвера
В исходной реализации в начале работы мы создавали необходимый класс драйвера, который затем передавали интерфейсному классу (Листинг 107). Но в интерфейсах системных API мы классы использовать не можем, как поступить в этом случае? Можно предложить следующее решение: класс драйвера создавать внутри API, а в функцию настройки передавать идентификатор, в соответствии с которым будет создан соответствующий драйвер (Листинг 108).
Листинг 107. Настройка драйвера в исходной реализации
ISensorControl sensorControl = ISensorControl::createControl;
DriverPointer driver = IDriver::createDriver(DRIVER_SIMULATION);
driver->initialize();
sensorControl->assignDriver(driver);
Листинг 108. Настройка драйвера в системном API (SensorLib.h)
thread_local sensor::DriverPointer g_DriverSimulation; // (1)
thread_local sensor::DriverPointer g_DriverUSB; // (2)
thread_local sensor::DriverPointer g_DriverEthernet; // (3)
void CreateDriver(sensor::DriverType driverType, sensor::DriverPointer& driverPointer) // (4)
{
if (!driverPointer)
{
driverPointer = sensor::IDriver::createDriver(driverType);
driverPointer->initialize();
}
g_SensorControl->assignDriver(driverPointer);
}
ErrorCode assignDriver(DriverType driverType) // (5)
Читать дальше