- PR -

C#のLock処理について

投票結果総投票数:8
Windows 8 100.00%
  • 投票は恣意的に行われます。統計的な調査と異なり、投票データの正確性や標本の代表性は保証されません。
  • 投票結果の正当性や公平性について、@ITは一切保証も関与もいたしません。
投稿者投稿内容
Bob
常連さん
会議室デビュー日: 2006/03/23
投稿数: 31
投稿日時: 2006-03-23 09:34
お世話になっております。

現在C#で作成したアプリが稼働中に、イベント処理ではlockにてスレッドの排他制御を行っています。最近、他スレッドでGC.Collect()を実施する前後で、lockで待ち中だったはずのスレッドが通知するイベントは何故かどこかに消えてしまったような事象が発生しています。
真相をまだ掴んでおらず、困っていますが、ガーベージコレクションは何らかの形で影響をもたらすことがありうるでしょうか?

以上、ご教授お願い致します。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-03-23 09:40
読解力がないせいなのか、仰っている事がよく分かりませんでした。
引用:

イベント処理ではlockにてスレッドの排他制御


というのは具体的にはどんな処理ですか?

引用:

lockで待ち中だったはずのスレッドが通知するイベント


lock で待ち中なのに通知するとはどういう事でしょうか?

詳細をお願いします。

_________________
囚人のジレンマな日々
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2006-03-23 09:53
現象が再現する最小限のプログラムを作ってみてください。
で、その作り方を教えてください。
Bob
常連さん
会議室デビュー日: 2006/03/23
投稿数: 31
投稿日時: 2006-03-23 11:12
説明不足で申し訳ありません(m__m)。
複雑なアプリの一部ですが、問題になるシナリオは下記にあります。なお、この問題の発生頻度はかなり低いですが、何らかの条件が揃ったときにのみ発生する感じです。

シナリオとして、
@ParentClassのStartでイベント処理が開始される
AProcessAが開始される
B上記Aが正常に開始されたら、ProcessBが開始される。
CProcessBが処理している間に、ProcessAの完了通知をアプリLogで確認できる
DProcessBの最後に、GC.Collect()が呼ばれることが確認出来る。
EProcessBの完了通知をアプリLogで確認できる。
FCallAnotherMethod()がずっと呼ばれない。
GParentClassのCancel()で終了処理がちゃんと出来ている(DeadLockが発生していないようで、どこにもExceptionが発生した痕跡も無かった)。

=====> 参考
コード:

public class EventHandleClass
{
private bool flagA = false;
private bool flagB = false;

public eventProcess(int eventID)
{
lock(this)
{
switch(eventID)
{
case 0:
// ProcessAには全てManagedCode
if(StartProcessA())
{
// ProcessBには、UnManagedCodeの内容があり、
// 終わりにGC.Collect()が必ず行われる
StartProcessB();
}
case 1:
flagA = true;
break;
case 2:
flagB = true;
break;
....
case 9:
....
break;
}

if(flagA && flagB)
{
CallAnotherMethod();
}
}
}

....
}

public class ParentClass
{
private EventHandleClass myEventHandler = null;

public ParentClass()
{
myEventHandler = new EventHandleClass();
}

// 外部Triggerより開始
public void Start()
{
myEventHandler.eventProcess(0);
}

// 他ThreadにてProcessAの完了を非同期で通知する
protected void ResultOfProcessA()
{
LogOut("Event-A received."); <= アプリのLogに表示あり
myEventHandler.eventProcess(1);
}

// 他ThreadにてProcessBの完了を非同期で通知する
protected void ResultOfProcessB()
{
LogOut("Event-B received."); <= アプリのLogに表示あり
myEventHandler.eventProcess(2);
}

public void Cancel()
{
myEventHandler.eventProcess(9);
}
}



[ メッセージ編集済み 編集者: Bob 編集日時 2006-03-23 18:58 ]
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-03-23 11:45
引用:

@ParentClassのStartでイベント処理が開始される


イベント処理とは?
他のプロセスを起動しているだけに見えます。

引用:

// 他ThreadにてProcessAの完了を非同期で通知する
// 他ThreadにてProcessBの完了を非同期で通知する


ProcessB の完了を通知した時、その「他Thread」は生きていますか?ParentClass の参照を保持していますか?

引用:

ParentClassのCancel()で終了処理がちゃんと出来ている


この根拠は?どこが呼びますか?もちろん ProcessA と ProcessB を呼び出した ParentClass と同じインスタンスですよね?
_________________
囚人のジレンマな日々
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2006-03-23 11:57
"C#パズル"みたいなソースですね。

StartProcessA()とStartProcessB()が終了した時に、どのようにしてResultOfProcessA()などを呼んでいるのか気になりますね。

コード:

public class ParentClass
{
private EventHandleClass myEventHandler = null;

private bool flagA = false;
private bool flagB = false;

public ParentClass()
{
myEventHandler = new EventHandleClass();
}

// 外部Triggerより開始
public void Start()
{
myEventHandler.eventProcess(0);
}

// 他ThreadにてProcessAの完了を非同期で通知する
protected void ResultOfProcessA()
{
LogOut("Event-A received."); <= アプリのLogに表示あり
myEventHandler.eventProcess(1);
flagA = true;
LogOut("A:" + flagA.ToString() + " B:" + flagB.ToString());

}

// 他ThreadにてProcessBの完了を非同期で通知する
protected void ResultOfProcessB()
{
LogOut("Event-B received."); <= アプリのLogに表示あり
myEventHandler.eventProcess(2);
flagB = true;
LogOut("A:" + flagA.ToString() + " B:" + flagB.ToString());

}

public void Cancel()
{
myEventHandler.eventProcess(9);
}
}



これ実行してみてください。
ちゃんと"A:true B:true"ってログに書かれます?

[ メッセージ編集済み 編集者: 一郎 編集日時 2006-03-23 11:59 ]
Bob
常連さん
会議室デビュー日: 2006/03/23
投稿数: 31
投稿日時: 2006-03-23 18:12
実際のClass構成は複雑なので、問題のところを抜粋するつもりで、概略にシナリオを書きましたが、分かりにくく、申し訳ありません。

Classの階層を書くと:

  • Layer-1:
    ManagerClass (Staticクラス、ParentClassの生成・Start/Cancel・Dispose等を制御する。

  • Layer-2:
    ParentClass(ManagerClassにDispose()されるまでに、ManagerClassは参照を持っている)

  • Layer-3:

    • EventHandleClass (ParentClassにて生成され、ParentがDisposeされるまでに、参照がParentClassにある)
    • ProcessAとは外部と通信するSubClassAの送信メソッドで、送信完了すれば、応答を待たない同期メソッドの感じ。
      なお、ParentClassは自分自身がDisposeされるまで、SubClassAの参照を持ち、オブジェクトを生成・制御している。
    • ProcessBとはEventHandleClassのDelegateに設定したParentClassのメソッドで、処理完了時に、BeginInvokeにて非同期にProcessBの処理完了を通知する。


引用:

イベント処理とは?
他のプロセスを起動しているだけに見えます。


ManagerClassからParentClassのStart指示です。

引用:

ProcessB の完了を通知した時、その「他Thread」は生きていますか?ParentClass の参照を保持していますか?


ResultOfProcessAとResultOfProcessBは非同期スレッドに同期にeventProcessで「lock」され、生きていると認識しています。

引用:

ParentClassのCancel()で終了処理がちゃんと出来ている
この根拠は?どこが呼びますか?もちろん ProcessA と ProcessB を呼び出した ParentClass と同じインスタンスですよね?



Layer-1のManagerClassが、ParentClassの生成・Start/Cancel制御も行われているので、ParentClassが先に進まないことを感知した上、Cancel処理だけは正常に終了しました。
従って、DeadLockが発生した可能性が低く、Result通知はどこかで紛失されたと疑っていますが。
_________________
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-03-23 19:10
引用:

スレッドが通知するイベントは何故かどこかに消えてしまったような事象が発生しています。


とか
引用:

従って、DeadLockが発生した可能性が低く、Result通知はどこかで紛失されたと疑っていますが。


ってどうやって確認してるんでしょうか?
というか、何を見て消えた、紛失した、と判断しているんでしょうか?

ps.
しかしまぁえらいプログラムですね…

--追記
失礼、CallAnotherMethodが呼ばれないからって書いてましたね…


[ メッセージ編集済み 編集者: なちゃ 編集日時 2006-03-23 19:14 ]

スキルアップ/キャリアアップ(JOB@IT)