C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 22 を表示中)
■9706 / )  Re[10]: System.Timers.Timerでのイベント処理
□投稿者/ れい (160回)-(2007/11/02(Fri) 16:14:41)
No9689 (nbmyou さん) に返信
>>でもスレ主さんは理解できたのかな?
>
> すみません。正直、半分も理解できていないと思います。
> そこで、数点質問させていただけますでしょうか。

あうー
だめでしたか。

> 質問の前に念のため、作成しようとしている監視の内容について概要をお伝えいたします。
> …
> 大雑把にこんな感じのものです。

大体わかったかんじです。

> @
> 上記に示したような内容の処理内容なので、重くてもスピード重視というよりは、
> 基本的に軽く動作するように実装したく思っております。それであれば、

ただの監視+DB登録なので、
多少遅れても問題なさそうですから、
スレッド一つに制限したほうがいいでしょう。

> A
> 無知で申し訳ないのですが、「ワーカースレッド」とは、
> 「作業を行うスレッド」というような意味合いで間違いありませんでしょうか。

OSから見たら普通のスレッドです。

コントロールスレッドとか、GUI用スレッドとか、
そういったものではなく、
作業用のスレッド、という意味合いです。

> A
> 上記の内容は、
>  ・System.Timers.Timerを使用する。
>  ・Sleepを使用する。(Thread.Sleepをタイマー代わりに使用するということでしょうか?)
> という2択を示してくださった、という認識で間違いありませんでしょうか。

この辺、うまく整理できません。
二つの概念がごっちゃになっています。

(1) 軽くするために暇なときにはスレッドを停止させないといけない。
(2) 5分に1回処理するために時刻を測らないといけない。

この二つの概念を実装しないといけません。

System.Timers.Timerを使うと、(1)、(2)共に自動で満たされます。
ですが必然的に再入が起こります。
再入を防ぐには、Interlockなど使う必要があります。

System.Timers.Timerは.Net依存ですが、
そうではない一般的方法で(1)を満たすには、
Sleepを使うか、同期オブジェクトのWaitを使うのが普通です。

Sleepを使うなら、例えば1秒間隔でSleepから復帰し、
時刻を確認して処理が必要な時刻になっていたら処理をし、
そうでないならまたSleepする、という方法で(2)を満たすことができます。

Waitを使うなら、タイムアウトを使ってSleepと同じように定期的に時刻を確認するか、
他のスレッドからイベント通知するという手で(2)を満たすことができます。
他のスレッドからイベント通知するなら、その「他のスレッド」は
System.Timers.Timerを使って、イベントにはAutoResetEventを使うのが楽です。

> 上記のどちらかの方法をお勧めしてくださっているのですよね?

どちらかではなく、Sleepを使う方法も加えて、3つの方法を書いていました。
前回聞いた範囲内でお勧めできそうなものは、その3つくらいだったので。

> これら上記どちらの方法を使用しても、同じ処理(タイマイベントで処理実行時、次のタイマイベントが発生しても、後のイベントは何もしない)を
> 行うことができるという認識で間違いありませんでしょうか。

そうですね。
私の述べた3つの方法はどれもそれをするための方法です。

あとはどう例外処理をするのかとか、
処理時間のほうが監視時間より長くなった場合どうするのかとか、
そういったことを考慮して選べばよいと思います。

> (処理に2分かかったとすると、実際には次の処理は7分後となる?)
> できれば、5分と設定したら、5分ごとに処理が行われるようにしたいので、
> それであればSleepを使う方法は、今回は避けようかと思っています。

これは、工夫次第ですよね。Sleepで時間を測れとは言っていません。
Sleepは時間を測るものではなく、待つものですから。
1秒間スリープしては現在時刻を見て、前回処理時刻と比較してもいいわけです。
用途によっては10秒間でも1分間隔でも良いかもしれません。

>>処理スピードがファイルを置くスピードよりも十分に速い事が保障できるのであれば、
>>仕組みを簡略化する事も可能でしょうし。
> 特に保障できるかは定かではありませんが、
> 簡略化するとは、たとえばどのような方法がありますでしょうか。

これに関しては、私は懐疑的です。
まず、処理スピードがファイルを置くスピードよりも十分に速い事を保証するのは困難です。
保証するコストと簡略化するコストでは、前者が圧倒的に大きいと思います。

プロセスをまたがったり、スレッドをまたがったりするときは
常に安全・安定な方向になるよう、気をつけないといけません。

> また、XMLファイルが作成途中(例えば大容量のファイルで、監視フォルダへのコピーに時間がかかっている状態)ではないことの判断は、
> 拡張子がaaa(仮)の同名ファイルが同じフォルダに存在するかどうかで判断します。

これはダメな方向であろうと思います。
ユーザーがaaaを作ってしまったらシステムが止まります。
また、XMLファイルを作成するプロセスが途中で殺されて、aaaが残ってしまっても同様です。
ファイルシステムで何かを保証しようと思ったら、
ファイルの存在ではダメで、ファイルのロックを使うべきです。

大体概要もわかったので、より詳細に私のお勧めを書いておきます。

OnStartか何かでワーカースレッド作成。
OnPauseやOnStopでは終了フラグや停止フラグを設定。
ワーカースレッドは無限ループ。
ループ内でSleep(1000)。
Sleepから戻ったらまず終了フラグや停止フラグの確認。
次に時刻の確認。
時刻が設定より過ぎていれば処理。そうでなければまたSleep。
処理を行うファイルは「排他」ロックをかける。「共有」ロックではなく。
排他ロックが取得できなければそのファイルは飛ばす。
DBに登録。その際、2重に登録されているなら飛ばす。
処理が終わったら、排他ロック解除後バックアップフォルダに「移動」。
移動が失敗した場合はあきらめる。

あまり真剣に考えてませんが、
これでたぶん安全に処理ができると思います。
どこで例外がおきても、どこでプロセスが殺されても、
大丈夫なように考えましょう。
返信 編集キー/


管理者用

- Child Tree -