我有以下代码,它从树莓派上的传感器读取温度。
代码是异步的,如果我只删除代码的最后一行,即发送消息的代码,我永远不会得到异常。 我的意思是这一行:
await deviceClient.SendEventAsync(message);
private async void InitializeSensors()
{
string calibrationData;
//_periodicTimer.Dispose();
// Inicializar el sensor bmp180
try
{
_bmp180 = new Bmp180Sensor();
await _bmp180.InitializeAsync();
calibrationData = _bmp180.CalibrationData.ToString(); //Retorna una cadena que representa al objeto actual.
if (_periodicTimer == null)
{
_periodicTimer = new Timer(this.TimerCallback, null, 0, readingInterval);
}
}
catch (Exception ex)
{
calibrationData = "Error de dispositivo! " + ex.Message;
}
var task = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
//calibrationDataTextBlock.Text = "";
});
}
public async void TimerCallback(object state)
{
string temperatureText;
// Leer datos del sensor
try
{
var sensorData = await _bmp180.GetSensorDataAsync(Bmp180AccuracyMode.UltraHighResolution);
temperatureText = sensorData.Temperature.ToString("");
//pressureText = sensorData.Pressure.ToString("F2");
temperatureText += "°C";
//pressureText += "hPa - " + BitConverter.ToString(sensorData.UncompestatedPressure);
var temperatureDataPoint = new
{
deviceKey = deviceKey,
deviceName = deviceName,
temperatura = sensorData.Temperature,
fecha = DateTime.Now
};
var messageString = JsonConvert.SerializeObject(temperatureDataPoint);
var message = new Microsoft.Azure.Devices.Client.Message(Encoding.ASCII.GetBytes(messageString));
message.Properties["Ambiente"] = ambiente;
////temperatura.Text = temperatureText;
await deviceClient.SendEventAsync(message);
}
catch (Exception ex)
{
temperatureText = "Sensor Error: " + ex.Message;
//pressureText = "Sensor Error: " + ex.Message;
}
//// actualizaciones de la interfaz de usuario... deben ser invocados en el subproceso de interfaz de usuario
var task = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
temperatura.Text = temperatureText;
});
}
如果删除线条,我可以看到传感器正在工作,因为文本框已使用真实的温度进行更新。
只有当我取消注释sendmessage行时,才会出现异常
我该如何解决这个问题?
答案 0 :(得分:1)
好的,看起来你有一些线程安全问题。
Per https://msdn.microsoft.com/en-us/library/microsoft.azure.devices.client.deviceclient.aspx,不保证任何(DeviceClient)实例成员都是线程安全的。
因此,当使用SendEventAsync之类的东西时,你的(也就是开发人员)有责任处理线程安全。
在您的情况下,当您启动计时器时,框架将在每次滴答时间时创建工作线程,这可能是一个问题,尤其是在延迟时间
await deviceClient.SendEventAsync(message);
是不确定的,所以你最终可能会有几个工作线程进行相同的SendEventAsync调用。
快速简单的解决方法是围绕此API调用添加AutoResetEvent(locker不同意等待),如下所示,
autoResetEvent.WaitOne();
await deviceClient.SendEventAsync(eventMessage);
autoResetEvent.Set();
将此autoResetEvent设为全局,以便它由所有工作线程共享。
PS:我看到你试图从一些Bmp180传感器上读取,你可能也希望这些调用也是线程安全的。
让我知道它是否适合你。