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

OK、スレッドセーフの問題があるようです。

https://msdn.microsoft.com/en-us/library/microsoft.azure.devices.client.deviceclient.aspxによると、( DeviceClientの) インスタンス メンバーはスレッド セーフであることが保証されていません。

そのため、SendEventAsync などを使用する際にスレッド セーフに注意するのは、開発者の責任です。

あなたの場合、タイマーを開始すると、フレームワークはティックが経過するたびにワーカースレッドを作成します。これは、特にレイテンシが発生する場合に問題になる可能性があります

await deviceClient.SendEventAsync(message);

は非決定論的であるため、複数の作業スレッドが同じ SendEventAsync 呼び出しを行うことになる可能性があります。

迅速かつ簡単な修正は、この API 呼び出しの周りに AutoResetEvent を追加することです (ロッカーは await に同意しません)。

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

この autoResetEvent をグローバルにして、すべてのワーカー スレッドで共有されるようにしてください。

PS: Bmp180 センサーから読み取ろうとしているようですが、これらの呼び出しをスレッドセーフにしたい場合もあります。

それがあなたのために働くかどうか私に知らせてください。

于 2016-09-29T01:56:46.517 に答える