1

これは奇妙に聞こえるかもしれませんが、はい、2009年であり、BCB5を使用して小さなアプリケーションを作成する必要があります:)

問題は、DynamicArray がワーカー スレッド内から展開しようとすると OutOfBound 例外をスローすることです。

私はグローバル変数を持っています、としましょう

DynamicArray<double> X;

メイン スレッドで配列の長さを確認すると、0 が返されます。これで問題ありません (長さが設定されていません)。

Application->MessageBox(itoa(X.Length,str , 10), "", MB_OK);

以下は私のワーカースレッドクラスです

class ArrayModifierThread : public TThread
{
private:
DynamicArray<double> __thread X;

protected:
void __fastcall Execute();

public:
__fastcall ArrayModifierThread(bool CreateSuspended);
 void setX(DynamicArray<double> &a);
};

ここまでは順調ですね。次に、新しいスレッドを作成します。

ArrayModifierThread *t = new ArrayModifierThread(true);
t->setX(X); // Pass reference to my global DynamicArray
t->Resume();

ここで Execute() メソッドが実行されます。

void __fastcall ArrayModifierThread::Execute()
{
 X.Length = 10;
 X[5] = 45.5;
}

私が期待するのは、グローバル配列が展開され、6 番目の要素が 45.5 の値を取得することです。

しかし、メイン スレッド内から詳しく調べると、Length = 0 と ArrayOfBounds Exception が返されます。

 Application->MessageBox(itoa(__X.Length,str , 10), "", MB_OK);
 Application->MessageBox(itoa(__X[5],str , 10), "", MB_OK);

私が見逃したことを誰か教えてもらえますか?

4

3 に答える 3

1

Executeメソッドでは、グローバル変数ではなく、スレッドの Xフィールドを変更しています。メソッドは参照によって引数を受け取りますが、メンバー変数は参照ではありませんX。値のコピーsetX格納し、プロパティを変更すると、一意の配列を参照するようになります。DynamicArrayLength

「回答」で正しく観察されているように、setX関数はグローバル変数への参照を受け取りますが、それへの参照は保持しません。X代わりに、オブジェクトのフィールドを割り当てるときにそのコピーを作成します。

Xおそらく、参照としても宣言するつもりでした。

private:
  DynamicArray<double>& X;

それはうまくいくかもしれません。初期setX化された後に参照を「再設定」することは許可されていないため、関数は機能しなくなります。代わりに、スレッドのコンストラクターで初期化する必要があります。

ArrayModifierThread(DynamicArray<double>& a): X(a) { ... }

参照の代わりに配列へのポインタを格納することもできます。

private:
  DynamicArray<double>* X;
public:
  void setX(DynamicArray<double>& a) {
    X = &a;
  }
protected:
  void Execute() {
    X->Length = 10;
    (*X)[5] = 45.5;
  }

他に注意する必要があるのは、コードがスレッドセーフではないということです。(どちらもここでは私のものではありません。)クリティカルセクションなどの保護なしで同じ共有リソース(アレイ)を変更する複数のスレッドがあります。ただし、これはこの質問の範囲を超えています。最初にStackOverflowとその他のWebを検索してから、その問題についてサポートが必要な場合は、戻って新しい質問をしてください。

于 2009-02-03T07:33:39.773 に答える
1

メンバー X は参照ではないため、機能しません。set() を呼び出すと、オブジェクトのローカル コピーが作成され、Execute() はローカル バージョンを変更します。

class ArrayModifierThread : public TThread
{
    private:
        DynamicArray<double> __thread X;


void __fastcall ArrayModifierThread::Execute()
{
    X.Length = 10;
    X[5] = 45.5;
 }

次の 3 つの代替ソリューションがあります。

ローカル メンバー変数 X を参照にします。
参照は構築時に初期化する必要があるため、 set() を使用して変更することはできません。参照をオブジェクトのコンストラクターに渡し、そこに保存します。

ローカル メンバ変数 X をポインタにします。set() を使用する場合、渡されたパラメーターのアドレスを取得します (これは参照であるため、参照しているオブジェクトのアドレスを取得することに注意してください)。これは、X がポインターであることを考慮して実行を変更する必要があることも意味します。

ローカル メンバー変数は使用しないでください。グローバルを直接変更するだけです。

于 2009-02-03T14:19:19.847 に答える
0

まあ、それは私にはよくわかりません。void setX(DynamicArray&a)が原因で、ワーカースレッドがグローバル変数への参照を取得すると思いました。

サンプルコードをどのように投稿すればよいですか?

これは私のvoidsetX(DynamicArray&a)がどのように見えるかです:

void ArrayModifierThread::setX(DynamicArray<double> &a)
{
   X = a;
}
于 2009-02-03T07:43:50.610 に答える