2017-01-16 35 views
0

これはDelphi 10.1 Berlin(おそらくパッチが適用されていません)です。 このコードはかなり基本的です。 このコードは、安定していません。Delphi BluetoothLE WriteCharacteristic Access Violation

なぜですか?

procedure TBLEEnumerator.WriteToSubScribedCharacteristic(bs: TArray<byte>); 
var 
    //member ble is an instance of TBluetoothLE 
    chr: TBluetoothGattCharacteristic; 
begin 
    chr := ble.GetCharacteristic(FBLEGattService, ChooseCharacteristic); 
    chr.SetValue(bs); 
    ble.WriteCharacteristic(self.dev, chr); 
end; 

他のいくつかの注意事項:Windows上で実行している場合 このエラーはあるが、私はこのコードは、モバイルデバイス上でも実行する予定。

この関数は、メインスレッドから呼び出され、TBluetoothLEコンポーネントのラッパーです。元の接続/スキャンは、メインスレッドからも処理されます。

明らかに簡単です。 TArrayは参照カウントの動的配列です。ときにタンク

はここでコールスタックです:

:761d31ce ucrtbase.memcpy + 0x4e 
System.Win.BluetoothWinRT.BytesToIBuffer(???,???) 
System.Win.BluetoothWinRT.TWinRTBluetoothGattCharacteristic.SetValueToDevice 
System.Win.BluetoothWinRT.TWinRTBluetoothLEDevice.DoWriteCharacteristic$52$ActRec.$0$Body 
System.Classes.TAnonymousThread.Execute 
System.Classes.ThreadProc($7511F40) 
System.ThreadWrapper($5A30D30) 
:740162c4 KERNEL32.BaseThreadInitThunk + 0x24 
:77060fd9 ; 
:77060fa4 ; 
+0

'chr'をローカルとして宣言しましたが、その値を設定しましたが、' self.chr'を 'WriteCharacteristic'に渡しました。あなたのローカル 'chr'は同じ名前のフィールドを隠しているようですが、あなたはそれらの使用を混乱させるようです...それは目的ですか?たぶん 'self.chr'は' nil'です...宣言しても何も使わなかったら?私はこれに[mcve]が必要だと思います。少しのデバッグもうまくいかないでしょう... 'ble.WriteCharacteristic'が呼び出されたときに' self.chr'が割り当てられていますか? –

+0

呼び出しスタックによれば、コードは匿名のスレッドで実行されるため、コードがスレッドセーフではない可能性があります。 – whosrdaddy

+0

self.chrは良い観察でした。しかし、それは修正ではありませんでした。私はchrをメンバーとして使うときにこの不安定さを見てからローカルに移動しました...しかし明らかに私は1つの部分を変更するのを忘れました。アプリケーションはまだクラッシュします。 – jason

答えて

1

は、ここでの契約です。これはEmbarcaderoライブラリのBUGです。はい、それでもおそらく修正されないバグです。

はここで自分のためにそれを修正する方法は次のとおりです。

  1. コピープロジェクトディレクトリにSystem.Win.BluetoothWinRT.pasまたはプロジェクトで使用されるいくつかの他のパス。
  2. IDEでファイルを開きます。
  3. 「BytestoBuffer」を検索してください。
  4. 関数のシグネチャから単語 "const"を削除します。

(FMXとVCLの作者を含む)これを実現する人はほとんどいませんが、 "const"文字列と動的配列を使用すると、Win32コンパイラはそれらの構造の参照カウント処理を最適化します。モバイルコンパイラやWin64コンパイラに影響するかどうかはわかりませんが、おそらくわかりません。

その厄介な効果は、その文字列または動的配列が別のスレッドから発生した場合、その別のスレッドが新しいスレッドの前にその文字列または動的配列を破棄することを非常にうまく決定する可能性があるということです(この場合、 - データの後ろに)その作業を終了します。

この機能からconstを削除すると、不安定性が修正されました。

+0

これは間違った修正のようです。同じオブジェクトへの参照を保持する2つのパーティーがあってはなりません。それはデータ競争につながる可能性があります。 FWIW constは、すべてのコンパイラのリファレンスカウントに同じ影響を与えます。そしてあなたが言うことは真実ではありません。このクラスは、スレッドExecuteメソッドがそれを参照できるように、ある時点で参照を取得する必要があります。私は確かに納得しています。バグレポートを提出しましたか? –

+0

@J ...スレッドの 'Execute'メソッドが、参照カウントを増やさずに配列にアクセスする方法がわかりません。確かにどこかにスレッドがアクセスできる変数がなければならず、その変数が割り当てられたときには、refカウントが増加していなければなりません。 –

+0

匿名スレッドは、唯一の実参照が無名関数のconstとして渡されるため、任意の場所への参照を保持しません。 BytesToIBufferに到達すると、参照カウントは無視され、誰も匿名スレッドで作業を完了するかどうかをチェックしたり待機したりすることはありません。したがって、1msまたは10000msのバッファが必要なことはわかっています。その間、呼び出し元のスレッドは、バッファが必要なものを自由に入れて、メモリのこの部分にアクセスするバックグラウンドプロセスを完全に知らない。 – jason

関連する問題