私はこの正確なトピックについて何も本当に見つけることができなかったので、質問がすでに存在する場合は、正しい方向に私を導いてください。
.NETについて学んだことから、異なるスレッド間で変数にアクセスすることはできません(そのステートメントが間違っている場合は修正してください。それはどこかで読んだものです)。
ただし、このコードサンプルでは、機能しないはずです。
_class MyClass
{
public int variable;
internal MyClass()
{
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();
}
public void DoSomething()
{
variable = 0;
for (int i = 0; i < 10; i++)
variable++;
MessageBox.Show(variable.ToString());
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void SomeMethod();
{
MyClass mc = new MyClass();
}
}
_
作成したオブジェクトmc
がmc
- initializer内で作成されたスレッドとは別のスレッドで実行されているため、SomeMethod()
を実行しても.NETは例外をスローしません。この新しいスレッドはmc
のローカル変数にアクセスしようとしていますか?
MessageBox
は_10
_を期待どおり(そうではない)示していますが、これが機能する理由がわかりません。
たぶん、何を検索すればいいかわからなかったが、見つけられたスレッディングトピックではこの問題に対処できなかったかもしれないが、変数とスレッドに関する私の考えが間違っているかもしれない。
.NETについて学んだことから、異なるスレッド間で変数にアクセスすることはできません。その記述が間違っている場合は訂正してください。それはどこかで読んだものです。
そのステートメントは完全に偽ですので、これはあなたの修正を考慮してください。
ローカル変数が異なるスレッド間でアクセスできないことをおそらくどこかで読んだでしょう。そのステートメントは also falseですが、一般的に述べられています。正しいステートメントは、
yield return
またはyield break
を持つメソッド)複数のスレッドからアクセスすることはできません。そして、その主張でさえ少し危険です。ポインタとunsafe
コードブロックでこれを行う方法はありますが、そうすることは非常に悪い考えです。
また、あなたの質問はローカル変数について尋ねていますが、 field の例を示しています。フィールドは、定義上、ローカル変数ではありません。ローカル変数は、定義によりメソッド本体にローカルです。 (またはコンストラクター本体、インデクサー本体など)。そのことを明確にしてください。ローカルの定義的な特徴は、それが「スタック上」またはそのようなものであることではありません。ローカルの「ローカル」部分は、その名前がメソッド本体の外では意味がないということです。
一般的な場合:変数はストレージロケーションであり、 memory を参照します。スレッドはプロセス内の制御点であり、プロセス内のすべてのスレッドは同じメモリを共有します。それが threads であり、 processes ではありません。したがって、一般に、すべての変数は、いつでもすべての順序で複数のスレッドからアクセスできます。ただし、それを防ぐためのメカニズムが導入されている場合を除きます。
繰り返しになりますが、あなたの心の中でそれが絶対にはっきりしていることを確認するために:シングルスレッドプログラムについて考える正しい方法は、何かがそれらを作らない限り、すべての変数が stable であるということです変化する。マルチスレッドプログラムについて考える正しい方法は、すべての変数が常に変化している特定の順序がない何かがまだ維持している場合を除いてまたは整然とした。 これが、マルチスレッディングの共有メモリモデルが非常に難しい基本的な理由です。したがって、それを避ける必要があります。
特定の例では、両方のスレッドがthis
にアクセスできるため、両方のスレッドが変数this.variable
を参照できます。これを防止するメカニズムを実装していないため、両方のスレッドがその変数に対して任意の順序で書き込みと読み取りを行うことができますが、実際にはほとんど制約がありません。この動作を制御するために実装できるメカニズムには、次のものがあります。
ThreadStatic
のマークを付けます。これにより、各スレッドで新しい変数が作成されます。volatile
のマークを付けます。これを行うと、読み取りと書き込みの順序付けを監視する方法に特定の制限が課され、また、予期しない結果を引き起こす可能性があるコンパイラまたはCPUによる最適化にも特定の制限が課されます。lock
ステートメントを置きます。マルチスレッディングとプロセッサの最適化について deep を理解していない限り、後者以外のオプションはお勧めしません。
ここで、別のスレッドで変数へのアクセスが失敗したことを確認したいとします。コンストラクターに作成スレッドのスレッドIDをキャプチャさせ、それを隠しておくことができます。次に、プロパティのゲッター/セッターを介して変数にアクセスし、ゲッターとセッターが現在のスレッドIDをチェックし、元のスレッドIDと異なる場合は例外をスローします。
基本的に、これは自分のシングルスレッドアパートメントスレッドモデルをロールします。 「シングルスレッドアパートメント」オブジェクトは、それを作成したスレッドでのみ正当にアクセスできるオブジェクトです。 (あなたはテレビを購入し、あなたのアパートにそれを置きます、あなたのアパートの人々だけがあなたのテレビを見ることを許可されます。)シングルスレッドアパート対マルチスレッドアパート対フリースレッドの詳細は非常に複雑になります。詳細については、この質問を参照してください。
これが、たとえば、UIスレッドで作成したUI要素にワーカースレッドからアクセスしてはならない理由です。 UI要素はSTAオブジェクトです。
私が.NETについて学んだことから、異なるスレッド間で変数にアクセスすることはできません(そのステートメントが間違っている場合は修正してください。それはどこかで読んだものです)。
不正解です。変数は、スコープ内のどこからでもアクセスできます。
複数のスレッドから同じ変数にアクセスする場合は注意が必要です。各スレッドは不確定な時間に変数に作用して、微妙で解決が難しいバグにつながる可能性があるためです。
基本から高度な概念まで、.NETのスレッディングをカバーする優れたWebサイトがあります。
私は少し遅れており、@ Eric J.の答えは素晴らしく、要点です。
スレッドと変数の認識に関する別の問題を少し明確にしたいと思います。
これは、質問のタイトル「別のスレッドで変数にアクセスできる」で述べています。これに加えて、コードでは、ここで作成されるスレッドである1スレッドから変数にアクセスしています:
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();
これらすべてのことから、MyClass
のインスタンスを実際に作成するスレッドとは別のスレッドが、そのインスタンス内の何かを使用するのではないかとおびえていることがわかりました。
次の事実は、マルチスレッドが何であるかをより明確に把握するために重要です(あなたが思ったよりも単純です)。
[〜#〜]編集[〜#〜]
thread safeという言葉がこの回答のスレッドに表示されます。これらの単語が何を意味するのか疑問に思われるかもしれませんが、@ Eric Lippertによるこの素晴らしい記事をお勧めします: http://blogs.msdn.com/b/ericlippert/archive/2009/10/19/what-is -this-thing-you-call-thread-safe.aspx
メモリの場所は単一のスレッドに分離されていません。もしそうなら、それは本当に不便でしょう。 CLRのメモリは アプリケーションドメイン 境界でのみ分離されます。 AppDomain ごとに各静的変数の個別のインスタンスがあるのはそのためです。ただし、 スレッドは特定の1つのアプリケーションドメインに関連付けられていません 。複数のアプリケーションドメインでコードを実行することも、何も実行しない(アンマネージコード)こともできます。彼らができないことは、同時に複数のアプリケーションドメインからコードを実行することです。これは、スレッドが2つの異なるアプリケーションドメインのデータ構造に同時にアクセスできないことを意味します。そのため、マーシャリング手法(MarshalByRefObject
など)を使用するか、.NET RemotingやWCFなどの通信プロトコルを使用して、別のアプリケーションドメインからデータ構造にアクセスする必要があります。
CLRをホストするプロセスの次のユニコードアート図を検討してください。
┌Process───────────────────────────────┐
│ │
│ ┌AppDomain───┐ ┌AppDomain───┐ │
│ │ │ │ │ │
│ │ ┌──────Thread──────┐ │ │
│ │ │ │ │ │
│ │ └──────────────────┘ │ │
│ │ │ │ │ │
│ └────────────┘ └────────────┘ │
└──────────────────────────────────────┘
各プロセスが複数のアプリケーションドメインを持つことができ、スレッドがそれらの複数のドメインからコードを実行できることがわかります。また、スレッドがアンマネージコードを実行できることを、左側と右側のAppDomainブロックの外側にも表示することで説明しました。
したがって、基本的にスレッドは、現在実行されている同じアプリケーションドメイン内の任意のデータ構造への重要なアクセスと重要なアクセスを持っています。ここでは、「重要な」という用語を使用して、あるクラスから別のクラスへのパブリック、保護、または内部メンバー。スレッドは、これが発生するのを決して防ぎません。ただし、リフレクションを使用すると、別のクラスのプライベートメンバーにもアクセスできます。それは私が重要なアクセスと呼んでいるものです。はい、それはあなたの側で少し多くの作業を伴いますが、リフレクションの呼び出しを完了した後は、特別なことは何も行われません(ちなみに、コードアクセスセキュリティによって許可される必要がありますが、それは別のトピックです)。ポイントは、スレッドが実行している同じアプリケーションドメイン内のほとんどすべてのメモリにアクセスできることです。
スレッドが同じアプリケーションドメイン内のほとんどすべてにアクセスできるのは、そうしないとめちゃくちゃに制限されるためです。マルチスレッド環境で作業する場合、開発者はクラス間でデータ構造を共有するために多くの追加の労力を費やす必要があります。
要点をまとめると:
1Singularity operating system であっても、.NETスレッドをオペレーティングシステムとハードウェアに直接マッピングしているように見えます
いいえ、後方にあります。データがまだスコープ内にある限り、データにアクセスできます。
反対の問題、つまり2つのスレッドが同時に同じデータにアクセスすることを防ぐ必要があります。これは競合状態と呼ばれます。これを防ぐためにlock
のような同期手法を使用できますが、誤って使用すると、デッドロックが発生する可能性があります。
チュートリアルについては 。NETのC#スレッド を参照してください。