古い管理されていない C++ の時代に戻ると、マルチスレッド アプリケーションのクリティカル セクションを信頼できました。そのため、現在 dotNet/C# を使用して、ロック メカニズムを中継していました。リソースをロックすることで、どのスレッドもコード内のそれらのリソースにアクセスできないと確信しました。
これは dotNet では当てはまらないようです!
Windows サービス アプリケーションがあります。サード パリティ OCX をホストする非表示のフォームを使用して、メイン マネージ スレッドを作成します。このスレッド内で、オブジェクトのリストに対するメッセージ ポンピングとポーリングを行います。このオブジェクトのリストは、このマネージ スレッド内の OCX によって起動されたイベントによって変更されます。
コードの簡略化された部分をここに投稿します。
public bool Start()
{
ServiceIsRunning = true;
m_TaskThread = new Thread(new ParameterizedThreadStart(TaskLoop));
m_TaskThread.SetApartmentState(ApartmentState.STA);
m_TaskThread.Start(this);
return true;
}
private void OnOCXEvent(object objToAdd)
{
lock(m_ObjectList)
{
m_ObjectList.Add(objToAdd); }
}
}
private void CheckList()
{
lock(m_ObjectList)
{
foreach(object obj in m_ObjectList)
{
...
}
}
}
[STAThread] // OCX requirement!
private void TaskLoop(object startParam)
{
try {
...
while (ServiceIsRunning)
{
// Message pump
Application.DoEvents();
if (checkTimeout.IsElapsed(true))
{
CheckList();
}
// Relax process CPU time!
Thread.Sleep(10);
}
} catch(Exception ex) {
...
}
}
あなたは私を信じません: CheckList で「リストが変更されました」という例外が発生しました! 8-/
そのため、いくつかのログを記録したところ、同じマネージ スレッドが CheckList foreach ループ内にあるときに OnOCXEvent が発生することに気付きました。確かに、ログ ファイルで同じマネージド スレッド ID を取得しました。
今、私は疑問に思っています:どうしてこれが起こるのでしょうか?より多くの win32 スレッドで単一のマネージ スレッドが実装されていますか?
なぜこれが起こっているのか誰かが説明してくれることを願っています。それで、この問題を解決できます。
ありがとう、ファビオ
私のメモ:
foreachループの前にリストのコピーを作成する問題を実際に解決しました。しかし、私はこの解決策が好きではありません。また、何が起こっているのかを理解するのも好きです。私は 3 番目のパリティ OCX コードを所有していませんが、CheckList ループ内で呼び出すメソッドは、発生した OCX イベントとは論理的に関係ありません。