0

我有以下代码从树莓派上的传感器读取温度。

代码是异步的,如果我只删除代码的最后一行,即发送消息的代码,我永远不会得到异常。我的意思是这一行:

 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 行时,我才会收到异常

我怎样才能解决这个问题?

4

1 回答 1

1

好的,看起来你有一些线程安全问题。

根据https://msdn.microsoft.com/en-us/library/microsoft.azure.devices.client.deviceclient.aspx,不保证(DeviceClient 的)任何实例成员都是线程安全的。

因此,在使用 SendEventAsync 之类的东西时,您(又名开发人员)有责任注意线程安全。

在您的情况下,当您启动计时器时,框架将在每次滴答声过去时创建工作线程,这可能是一个问题,尤其是当

await deviceClient.SendEventAsync(message);

是不确定的,因此您最终可能会导致多个工作线程进行相同的 SendEventAsync 调用。

一个快速简单的解决方法是在这个 API 调用周围添加一个 AutoResetEvent(储物柜不同意等待),如下所示,

autoResetEvent.WaitOne();
await deviceClient.SendEventAsync(eventMessage);
autoResetEvent.Set();

请务必将此 autoResetEvent 设为全局,以便所有工作线程共享它。

PS:我看到您正在尝试从某些 Bmp180 传感器中读取数据,您可能也想让这些调用成为线程安全的。

请让我知道这对你有没有用。

于 2016-09-29T01:56:46.517 回答