1

次の同期の問題があります。

スレッドはループで実行され、まだ処理されていないファイルシステム内のフォルダー (アプリが実行されていない間に追加された可能性があります) が検出された場合、そのフォルダーはProcessメソッドによって新しいフォルダーとして処理されます。

void Loop()
{
 while (run)
 {
  lock(renameLock)
  {
    var newFolders = EnumerateNewFolders().ExceptThoseMarkedAsRenamed();
    Process(newFolders);
    MarkAsProcessed(newFolders);
  }
  Sleep();
 }
}

名前を変更したフォルダは、新しいものとして処理するのではなく、後で新しいものとして処理されないように、名前を変更したものとして処理し、名前を変更したものとしてマークする必要があります。

これを処理するために、イベントFileSystemWatcher用の および ハンドラーがあります。Renamed

private void fsw_Renamed(object sender, RenamedEventArgs e)
{
  lock(renameLock)
  {
    ProcessRename(e);
    //mark folder as renamed so that ExceptThoseMarkedAsRenamed filters it out
    MarkAsRenamed(e);
  }
}

通常、これは機能し、名前の変更が実行されると、フォルダーは最初に名前が変更されたものとしてマークされfsw_Renamed、次にループでフィルターExceptThoseMarkedAsRenamed処理され、新しいものとして処理されません。

ただし、次の順序が発生する場合があります。

  1. Windows エクスプローラーとファイルシステムでフォルダーの名前が変更されます (ループがロックを保持している間)。
  2. fsw_Renamed が発生するが、ロックを取得できない
  3. ループ スレッドはまだロックを保持しており、フォルダを新しいものとして取得します (まだ名前が変更されたものとしてマークされていません)。
  4. ループ スレッドはロックを解放します
  5. 名前変更イベントが発生し、ロックが取得され、フォルダーが名前変更済みとしてマークされます。しかし、すでに新品として処理されているため、手遅れです。

名前を変更したフォルダーが新しいフォルダーとして処理されないようにする方法がわかりません。

名前が変更されたフォルダは、ファイル システムの変更とイベントの間に固有の遅延があるため、Renamedイベントが発生した、または近い将来発生するFileSystemWatcher.Renamedフォルダです(ファイル システムの実際の変更と発生したイベントはアトミックではありません)。

ループがロックを保持している間にイベントが発生した場合でも、fsw_Renamed によって行われた変更が常にループによって考慮されるようにする方法は?

4

2 に答える 2

1

次のことを試すことができます。

  1. アプリケーションの起動時にのみLoopメソッドを実行します。おそらく、にサブスクライブする前に。FileSystemWatcher
  2. をサブスクFileSystemWatcher.Createdライブしたディレクトリで をサブスクライブしFileSystemWatcher.Renamedます。
  3. サブスクリプションはそのままにしてくださいFileSystemWatcher.Renamed
  4. 2 つのイベントが互いに競合してはならないため、ロックを解除します。

ステップ 1. は、アプリケーション実行されていない間に作成/名前変更されたディレクトリを処理します。

ステップ 2. では、アプリケーションの実行中に新しいディレクトリを処理します。

ステップ 3. は、アプリケーションの実行中に名前が変更されたディレクトリを処理します

于 2012-11-21T16:05:06.403 に答える
1

フォルダを処理したいと考えています。フォルダが新しいか、単に名前が変更されたかに応じて、2 種類の処理を行います。特定のフォルダーの名前が変更されたときにイベントを発生させる fs 監視オブジェクトを使用しています。新しいフォルダーにも同様の監視を使用し、これらのイベントでフォルダーにバインドされたタスクを作成する必要があります。

イベントをキャッチするスレッドには競合状態の問題はなく、新しいタスクのみをディスパッチするため、処理によって遅延することはなく、新しいイベントが発生したときに処理することができます。タスク キューは、単純に、フォルダとそれに適用するタスクを含むペアのリストである可能性があります。

フォルダーの処理がスケジュールされている場合、タスク キューをチェックしてフォルダーがそこにあるかどうかを確認することにより、フォルダーに発生するイベントをモニターでフィルター処理する必要があります。他の要因に応じて、タスクを変更したり削除したりすることもできます (たとえば、処理される前にフォルダーが削除された場合、そのイベントも監視することをお勧めします)。

タスクは次のようなものです。

  • 処理するフォルダーをロックします (これにより、フォルダーへの外部からの影響が回避されます)。
  • 処理する
  • 「処理済み」としてマークします(リストから削除します)
  • ロックを解除する

そもそも問題を引き起こしているので、 renameLock を保持することはできません。フォルダをロックできない場合は、おそらくそれを別の場所に移動して(技術的には名前の変更に似ていると思います)、処理を行ってから元の場所に戻すことができます。

このSO の質問は、C# でフォルダーをロックする問題を扱います。

于 2012-11-21T13:39:21.090 に答える