// Static Constructor static EventEmailWriter() { RecentLineEvents = new HashSet <LineEvent>(); QueuedLineEvents = new HashSet <LineEvent>(); EmailProcessingThread = new LogicalThread(); EmailProcessingThread.UnhandledException += (sender, args) => Log.Error(args.Argument.Message, args.Argument); PurgeOldLineEventsAction = new Action(PurgeOldLineEvents); }
// Release any unmanaged resources. // This may not necessarily unload islands or dynamic modules that were created until the calling appdomain has exited. public void Exit(int threadIndex) { Fx.Assert(threadIndex >= 0, "Invalid thread index"); Fx.Assert(this.threads[threadIndex] != null, "Cannot dispose null LogicalThread"); LogicalThread thread = this.threads[threadIndex]; thread.Exit(); // Null the entry on the List for future reuse. this.threads[threadIndex] = null; }
// Forces enumeration of directories currently being watched. private async Task EnumerateWatchDirectoriesAsync() { List <TrackedDirectory> GetTrackedDirectories() { lock (m_trackedDirectoriesLock) return(new List <TrackedDirectory>(m_trackedDirectories)); } List <TrackedDirectory> trackedDirectories = GetTrackedDirectories(); FileEnumerationStrategy enumerationStrategy = m_enumerationStrategy; bool sequential = enumerationStrategy == FileEnumerationStrategy.Sequential; Func <LogicalThread> getEnumerationThread = sequential ? () => m_sequentialEnumerationThread : () => m_threadScheduler.CreateThread(); async Task EnumerateTrackedDirectoryAsync(TrackedDirectory trackedDirectory) { try { LogicalThread enumerationThread = getEnumerationThread(); await enumerationThread.Join(); await trackedDirectory.EnumerateAsync(enumerationStrategy); } catch (Exception ex) { OnError(ex); } } IEnumerable <Task> enumerationTasks = trackedDirectories .Select(EnumerateTrackedDirectoryAsync); async Task ForEach(IEnumerable <Task> tasks) { foreach (Task task in tasks) { await task; } } Func <IEnumerable <Task>, Task> whenAll = sequential ? ForEach : Task.WhenAll; await whenAll(enumerationTasks); }
/// <summary> /// Creates a new instance of the <see cref="FileProcessor"/> class. /// </summary> public FileProcessor() { m_filter = DefaultFilter; m_folderExclusion = DefaultFolderExclusion; m_trackChanges = DefaultTrackChanges; m_internalBufferSize = DefaultInternalBufferSize; m_enumerationStrategy = DefaultEnumerationStrategy; m_trackedDirectoriesLock = new object(); m_trackedDirectories = new List <TrackedDirectory>(); m_enumerationOperation = new TaskSynchronizedOperation(EnumerateWatchDirectoriesAsync, OnError); m_threadScheduler = new LogicalThreadScheduler(2); m_threadScheduler.UnhandledException += (sender, args) => OnError(args.Argument); m_processingThread = m_threadScheduler.CreateThread(); m_watcherThread = m_threadScheduler.CreateThread(); m_sequentialEnumerationThread = m_threadScheduler.CreateThread(); m_fileWatchTimer = new Timer(15000); m_fileWatchTimer.Elapsed += FileWatchTimer_Elapsed; m_requeueTokenSource = new ManagedCancellationTokenSource(); m_touchedFiles = new Dictionary <string, DateTime>(StringComparer.OrdinalIgnoreCase); }
private async Task EnumerateDirectoryAsync(DirectoryInfo directory, FileEnumerationStrategy fileEnumerationStrategy, CancellationToken cancellationToken) { bool parallelSubdirectories = fileEnumerationStrategy == FileEnumerationStrategy.ParallelSubdirectories; LogicalThread thread = LogicalThread.CurrentThread; if (parallelSubdirectories) { LogicalThreadScheduler scheduler = m_fileProcessor.m_threadScheduler; thread = scheduler.CreateThread(); await thread.Join(); } async Task ForEach(IEnumerable <Task> tasks) { foreach (Task task in tasks) { if (cancellationToken.IsCancelled) { return; } await task; await thread.Yield(); } } LogicalThread processingThread = m_fileProcessor.m_processingThread; string activePath = null; async Task VisitSubdirectoryAsync(DirectoryInfo subdirectory) { activePath = subdirectory.FullName; if (cancellationToken.IsCancelled) { return; } if (m_fileProcessor.MatchesFolderExclusion(subdirectory.FullName)) { return; } await EnumerateDirectoryAsync(subdirectory, fileEnumerationStrategy, cancellationToken); } async Task <Task> VisitFileAsync(FileInfo file) { activePath = file.FullName; if (cancellationToken.IsCancelled) { return(Task.CompletedTask); } async Task InvokeOnProcessingThread(Action action) { await processingThread.Join(); action(); } DateTime lastWriteTime = file.LastWriteTimeUtc; void Process() => m_fileProcessor.TouchAndProcess(file.FullName, lastWriteTime, false); void Skip() => m_fileProcessor.TouchAndSkip(file.FullName, lastWriteTime); if (!m_fileProcessor.MatchesFilter(file.FullName)) { return(InvokeOnProcessingThread(Skip)); } Task processTask = InvokeOnProcessingThread(Process); await thread.Yield(); return(processTask); } async Task EnumerateSubdirectoriesAsync() { Func <IEnumerable <Task>, Task> whenAll = parallelSubdirectories ? Task.WhenAll : ForEach; IEnumerable <Task> subdirectoryTasks = FilePath .EnumerateDirectories(directory, "*", SearchOption.TopDirectoryOnly, m_fileProcessor.OnError) .Select(VisitSubdirectoryAsync); await whenAll(subdirectoryTasks); } async Task EnumerateFilesAsync() { IEnumerable <Task <Task> > fileTasks = FilePath .EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly) .Select(VisitFileAsync); List <Task> processTasks = new List <Task>(); foreach (Task <Task> fileTask in fileTasks) { processTasks.Add(await fileTask); } await Task.WhenAll(processTasks); } EventHandler <EventArgs <List <string> > > handler = (sender, args) => { if (!(activePath is null)) { args.Argument.Add(activePath); } }; try { ActivelyVisitedPathsRequested += handler; if (parallelSubdirectories) { Task subdirectoriesTask = EnumerateSubdirectoriesAsync(); await EnumerateFilesAsync(); ActivelyVisitedPathsRequested -= handler; await subdirectoriesTask; } else { await EnumerateFilesAsync(); await EnumerateSubdirectoriesAsync(); } } finally { ActivelyVisitedPathsRequested -= handler; } }