- PR -

ファイル監視:FileSystemWatcherクラス....

投稿者投稿内容
ふぁん
会議室デビュー日: 2003/05/20
投稿数: 9
投稿日時: 2003-07-02 13:24
FTPでフィアルを受信したら、Eventを発生させ処理すると言うツールを開発中です。
Microsoftのぺーじを参照にFileSystemWatcherクラスを使って作成しまして
うまく動作はしますが、CPUがいつも100%になってしまいます。

以下のぺーじでサンプルを参考に作成しましたが、サンプルを実行しても同じ現象が起こります。何か解決方法は無いでしょうか。

サンプルコード:
using System;
using System.IO;

public class Watcher
{

public static void Main()
{
// string[] args = System.Environment.GetCommandLineArgs();

// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"d:\test";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = true; //サブDIRも監視

watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);

while(true){
watcher.EnableRaisingEvents = true;
}
}

// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}

private static void OnRenamed(object source, RenamedEventArgs e)
{
// Specify what is done when a file is renamed.
Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
}
cats
大ベテラン
会議室デビュー日: 2002/11/29
投稿数: 221
お住まい・勤務地: 東京
投稿日時: 2003-07-02 18:10
Mainの最後のwhileを以下のように変えれば、100%になりません。
(以下は、ヘルプからのコピーです)
コード:
        watcher.EnableRaisingEvents = true;
        Console.WriteLine("Press \'q\' to quit the sample.");
        while(Console.Read()!='q');

ふぁん
会議室デビュー日: 2003/05/20
投稿数: 9
投稿日時: 2003-07-02 23:11
catsさんありがとうございます。
windowsConsoleプログラムではこれでOKになりました。

私はこれをwindowsサービスかしたため、
Console.WriteLine("Press 'q' to quit the sample.");
while(Console.Read()!='q');

while (true) ; に直しました。
それがCPU100%になってしまうのはちょっと理解し難いです。

一応方法は探して見ます。
結果がある次第ご報告いたします。
まりり
ぬし
会議室デビュー日: 2001/12/05
投稿数: 329
投稿日時: 2003-07-03 00:03
> 私はこれをwindowsサービスかしたため、
> Console.WriteLine("Press 'q' to quit the sample.");
> while(Console.Read()!='q');
> を
> while (true) ; に直しました。
> それがCPU100%になってしまうのはちょっと理解し難いです。

Console.Read()って入力あるまで待ってたりしないです?

 while(Console.Read()!='q'){ Console.WriteLine("-"); }

とかやって-がいくつ表示されるか試してみてはいかがでしょう?
ya
大ベテラン
会議室デビュー日: 2002/05/03
投稿数: 212
投稿日時: 2003-07-03 05:26
while(true);
だとひたすらこのスレッドがうごきつづける事になりますので当然100%になってしまいます。邪道ですがこのコードだと一番簡単には…

while(true)System.Threading.Thread.CurrentThread.Sleep(100);
(100の部分はなんか適当に)

とでもすればたぶん使用率は減ると思いますが。

でも、本当はこの何もする必要のないスレッドを無駄に動かしているわけで、なんとかしたいものだとおもうのですが。FileSystemWatcherのWaitForChangedメソッドもスレッド同期化につかうみたいで微妙な感じだし…。
なな
ぬし
会議室デビュー日: 2003/06/22
投稿数: 659
お住まい・勤務地: 愛知県
投稿日時: 2003-07-03 08:38
> while(true);

何も処理する必要が無いのならば、
System.Threading.Thread.CurrentThread.Suspend();
するのが良いと思います。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-07-03 08:46
こんにちは。

 イベントが発生するまで、単純に待っていればいいんですよね?

FileSystemWatcher.WaitForChanged(
WatcherChangeTypes changeType,
int timeout
);

こっちを使います。timeoutを-1にすればいつまでも待ちます。待っている間はCPU時間を消費しません。

 別に、他に何か処理させているわけではないですよね?変更があるまでじっと待ち、変更があったら何らかの処理を行い、その処理がすんだらまた変更があるまで待つ、でいいんですよね?そうであるなら、イベントに登録するのではなく、メソッド呼び出しで十分だと思います。
 もっとも、Windowsアプリなら、イベントに登録します。windowsアプリは、Formを描画するという大切な処理をメインで行う必要があるので、イベントに登録します。


てきとー
using System;
using System.IO;

public class Watcher
{

public static void Main()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"d:\test";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = true; //サブDIRも監視

while (true) {
WaitForChangedResult result = watcher.WaitForChanged(WatcherChangeTypes.All, -1);
if (result.ChangeType == WatcherChangeTypes.Renamed) {
// Rename
Console.WriteLine("File: {0} renamed to {1}", result.OldName, result.Name);
} else {
// other
Console.WriteLine("File: {0} {1}", result.OldName, result.ChangeType);
}
}
}
}



>while (true) ; に直しました。
>それがCPU100%になってしまうのはちょっと理解し難いです。

 「trueがtrueか?」という判断(比較)をします。ここでCPUを消費します。次の実行文に移ります。ないので条件判断に戻ります。「trueがtrueか?」という判断でCPUを消費します。・・・というのが少しの休みもなく延々と繰り返されます。人間なら、「何か起こるまで待っていればいいんだな」と理解しますが、コンピュータは馬鹿正直に命令を実行します。従って、待たずに延々と判断し続けます。こういう訳で、CPUが100%になるのは、至極当然です。

[ メッセージ編集済み 編集者: Jitta 編集日時 2003-07-03 08:52 ]
ふぁん
会議室デビュー日: 2003/05/20
投稿数: 9
投稿日時: 2003-07-09 18:24
ようやくサービス化した時に永遠に動きながら、CPU100%にならない方法を見つけました。

public static void Main()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"d:\test";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = true; //サブDIRも監視
while (watcher.Equels("")==true) ;
}
while(true);  の代わりに while (watcher.Equels("")==true) ;
まず、trueになることが無いので、永遠に監視することになると思いますし、
watcherに対する比較ですのでEventが発生する度に比較するだけだと思います。
一応私のところでは検証済みです。

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