- PR -

C#のLock処理について

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

ちなみに
コード:

lock( this )


というのは,今ではかなり悪いロックのやり方であると言われています.これでは実際にロックしたい箇所がロックできない事が大いに有り得ますからね.詳細は調べてみてください.



お世話になっております。
このロックの仕方について、いろいろ調べましたが、下記の記事では説明がありますがロック出来ないケースは中々浮かんできませんので、ニ三ご教授いただけませんか?

http://msdn.microsoft.com/msdnmag/issues/03/01/NET/


[ メッセージ編集済み 編集者: Bob 編集日時 2006-03-27 14:03 ]
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-03-27 14:30
多分大嘘ついてしまったかも…。
ロックできないケースではなく、すぐにデッドロックしてしまうでした…。すみません。
#そんなケースがあったような気がしたんですが脳から出てこない…。

なんでデッドロックしてしまうかと言うと、this ではロックするものが大きすぎて、違う箇所で違う目的で同じ参照をロックしてしまう可能性を秘めているからです。
_________________
囚人のジレンマな日々
Bob
常連さん
会議室デビュー日: 2006/03/23
投稿数: 31
投稿日時: 2006-03-27 21:46
皆様から多くの指摘を頂き、ありがとうございます。
開示内容について、Jittaさんの仰るとおりですが、うまく出来なかった点について反省しております。一応、現時点調査してことをご報告いたします。

引用:

Jittaさんの書き込み (2006-03-24 21:36) より:
1.GC.collect によって回収されるもの


Thread及びBeginInvoke両方とも下記の方法で試した結果、現状スレッドがGCに回収されたことがありませんでした。

コード:
void caller() {
    executeThread();
    GC.Collect();
}

void executeThread() {
    Thread t = new Thread(someMethod());
    t.Start();
}



引用:

2.処理の実行順序
 この情報は提示されていません。
 意図通りに処理が実行されているのか、確認する必要があります。これは単純に、時間とスレッド ID、通過ポイントを出力して確認するということでいいでしょう。


意図としては、ProcessA と ProcessBの結果は順不同で、受け取った結果が処理されないことは依然原因不明です。

引用:

3.ロックの範囲



この点について、当方はかなり改善する余地があります。現状、大抵
コード:
lock(this)


のやり方でロックしているし、スレッド数もかなり多いので、タイミングにより何か影響している可能性もあります(BeginInvokeで生成することが多い)。

引用:

4.順次処理したい処理
 この情報は提示されていません。
 ProcessA と ProcessB が終了していれば、AnotherMethod を実行するということはわかりました。しかし、ProcessB だけが実行されることもある、とのことです。この辺りのメソッドが実行されるユースケース、および条件が整理されていないように感じます。少なくとも、私は読み取れませんでした。



大変申し訳ありません。やはりどこかで書き間違ったかもしれません。ProcessBだけが実行されることがなく、両者とも実行完了した通知を受けた場合のみ、AnotherMethod が実行される。いま、両者のEventハンドラで通知を受けたことが確認出来たが、AnotherMethodが実行されない原因を追求しているところです。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-03-27 22:11
これ→Threading Tips: Never Lock a Value Type. Never Lock "This".

Google 検索: lock "this"
(this を2重引用符で囲む)
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-03-27 22:23
引用:

Bobさんの書き込み (2006-03-27 21:46) より:

引用:

1.GC.collect によって回収されるもの


Thread及びBeginInvoke両方とも下記の方法で試した結果、現状スレッドがGCに回収されることがありませんでした。


私も確認しました。
 これにより、当初疑われていた、GC によってスレッドが破棄されることはない、といえると思います。

# 不思議だ。何で Dispose しなくていいんだろう?
# スレッドハンドルはどうなっちゃうんだろう?


引用:

引用:

2.処理の実行順序
 この情報は提示されていません。
 意図通りに処理が実行されているのか、確認する必要があります。これは単純に、時間とスレッド ID、通過ポイントを出力して確認するということでいいでしょう。


意図としては、ProcessA と ProcessBの結果は順不同で、受け取った結果が処理されないことは依然原因不明です。


 ん〜ん?でも、eventID 0 の時は、A → B ですよね?そういう風にコーディングされていますよね?
 おそらく、eventID 3〜8 のどれかで、B が起動されるのかもしれません。

 で、4も関係するのですが、何かひとつの処理が実行されていれば、ほかの呼び出しはすべてブロックされています。であれば、スレッドを使う意味がないのでは?と思います。

引用:

大変申し訳ありません。やはりどこかで書き間違ったかもしれません。ProcessBだけが実行されることがなく、両者とも実行完了した通知を受けた場合のみ、AnotherMethod が実行される。いま、両者のEventハンドラで通知を受けたことが確認出来たが、AnotherMethodが実行されない原因を追求しているところです。


 まず、呼び出しタイミングで、スレッド ID と、なんのための呼び出しかを記録できるようなコードを追加してください。
 そして、タスクマネージャにスレッド数が見られるように列を追加し、スレッドの生成と終了のタイミングを見てみてください。

 あと、フラグを false にするタイミングはないですか?
 おそらく、ブロックされているスレッドが解除される順番は、期待できないと思います(lock の前後にスレッド ID をログにはき出せば確認できます)。このため、順番的には A も B も true になっているのに、false する呼び出しが先に処理され、結果的に実行されていないのかもしれません。
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-03-27 23:11
引用:

# 不思議だ。何で Dispose しなくていいんだろう?



マネージスレッドはマネージ資源だからでは?

# ↑だけ見て書いてるので、間違っていたらごめんなさい。
Bob
常連さん
会議室デビュー日: 2006/03/23
投稿数: 31
投稿日時: 2006-03-28 00:25
引用:

Jittaさんの書き込み (2006-03-27 22:11) より:
これ→Threading Tips: Never Lock a Value Type. Never Lock "This".

Google 検索: lock "this"
(this を2重引用符で囲む)


ありがとう御座います。
何故か、文書が開けないみたいですが。。。

開けました。大変参考になりました。

ただ、一つ疑問になるのは、下記の例では異なるスレッドでlockFunc1()とlockFunc2()が呼ばれたら、お互いにロックすることが全くないと思います。そうすると、「ロックの対象となるオブジェクトが全く同じものではないとロックが機能しない」との認識は正しいでしょうか?

コード:

public class Sample()
{
public void lockFunc1()
{
lock(this)
{
// statements
}
}

private object lockObject = new object();

public void lockFunc2()
{
lock(lockObject)
{
// statements
}
}
}



[ メッセージ編集済み 編集者: Bob 編集日時 2006-03-28 09:24 ]
Bob
常連さん
会議室デビュー日: 2006/03/23
投稿数: 31
投稿日時: 2006-03-28 09:16
引用:

渋木宏明(ひどり)さんの書き込み (2006-03-27 23:11) より:
引用:

# 不思議だ。何で Dispose しなくていいんだろう?



マネージスレッドはマネージ資源だからでは?

# ↑だけ見て書いてるので、間違っていたらごめんなさい。




自分の認識だと、BeginInvokeで生成されThreadのハンドルはプロセス毎のThreadPoolにて管理され、決まったタイミングで開放されるのではと思います。

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