Windows服务:从配置文件中要监视的目录列表生成一组FileWatcher对象,具有以下要求:

>文件处理可能非常耗时 – 必须在自己的任务线程上处理事件
>保持事件处理程序任务的句柄以等待OnStop()事件中的完成.
>跟踪上传文件的哈希值;如果没有不同,不要重新处理
>保留文件哈希值以允许OnStart()处理服务关闭时上载的文件.
>永远不要多次处理文件.

(关于#3,我们确实在没有变化的情况下获取事件…最值得注意的是因为FileWatchers的重复事件问题)

要做这些事情,我有两个字典 – 一个用于上传文件,另一个用于任务本身.这两个对象都是静态的,我需要在添加/删除/更新文件和任务时锁定它们.简化代码:

public sealed class TrackingFileSystemWatcher : FileSystemWatcher {

    private static readonly object fileWatcherDictionaryLock = new object();
    private static readonly object runningTaskDictionaryLock = new object();

    private readonly Dictionary<int,Task> runningTaskDictionary = new Dictionary<int,Task>(15);
    private readonly Dictionary<string,FileSystemWatcherProperties>  fileWatcherDictionary = new Dictionary<string,FileSystemWatcherProperties>();

    //  Wired up elsewhere
    private void OnChanged(object sender,FileSystemEventArgs eventArgs) {
        this.ProcessModifieddatafeed(eventArgs);
    }

    private void ProcessModifieddatafeed(FileSystemEventArgs eventArgs) {

        lock (TrackingFileSystemWatcher.fileWatcherDictionaryLock) {

            //  Read the file and generate hash here

            //  Properties if the file has been processed before
            //  ContainsNonNullKey is an extension method
            if (this.fileWatcherDictionary.ContainsNonNullKey(eventArgs.FullPath)) {

                try {
                    fileProperties = this.fileWatcherDictionary[eventArgs.FullPath];
                }
                catch (KeyNotFoundException keyNotFoundException) {}
                catch (ArgumentNullException argumentNullException) {}
            }
            else {  
                // Create a new properties object
            }


            fileProperties.ChangeType = eventArgs.ChangeType;
            fileProperties.FileContentsHash = md5Hash;
            fileProperties.LastEventTimestamp = DateTime.Now;

            Task task;
            try {
                task = new Task(() => new datafeedUploadHandler().Uploaddatafeed(this.legalOrg,datafeedFileData),TaskCreationoptions.LongRunning);
            }
            catch {
              ..
            }

            //  Only lock long enough to add the task to the dictionary
            lock (TrackingFileSystemWatcher.runningTaskDictionaryLock) {
                 try {
                    this.runningTaskDictionary.Add(task.Id,task);  
                }
                catch {
                  ..
                }    
            }


            try {
                task.ContinueWith(t => {
                    try {
                        lock (TrackingFileSystemWatcher.runningTaskDictionaryLock) {
                            this.runningTaskDictionary.Remove(t.Id);
                        }

                        //  Will this lock burn me?
                        lock (TrackingFileSystemWatcher.fileWatcherDictionaryLock) {
                            //  Persist the file watcher properties to
                            //  disk for recovery at OnStart()
                        }
                    }
                    catch {
                      ..
                    }
                });

                task.Start();
            }
            catch {
              ..
            }


        }

    }

}

在同一对象的锁定中定义委托时,在ContinueWith()委托中请求锁定FileSystemWatcher集合的效果是什么?我希望它没问题,即使任务在ProcessModifieddatafeed()释放锁之前启动,完成并进入ContinueWith(),任务线程也会被暂停,直到创建线程释放锁.但我想确保我没有踩到任何延迟执行的地雷.

看一下代码,我可以尽快释放锁,避免问题,但我还不确定……需要检查完整的代码才能确定.

UPDATE

为了遏制不断上升的“这段代码很糟糕”的评论,我有很好的理由抓住我做的例外情况,并抓住了很多这样的例子.这是一个具有多线程处理程序的Windows服务,它可能不会崩溃.永远.如果其中任何一个线程有未处理的异常,它会做什么.

此外,这些例外写入未来的防弹.我在下面的评论中给出的示例是为处理程序添加工厂……因为今天编写的代码,永远不会有空任务,但如果工厂没有正确实现,代码可能抛出异常.是的,那应该在测试中被捕获.但是,我的团队中有初级开发人员……“May.不.崩溃.” (另外,如果存在未处理的异常,它必须正常关闭,允许当前正在运行的线程完成 – 我们使用main()中设置的未处理异常处理程序).我们将企业级监视器配置为在事件日志中出现应用程序错误时发送警报 – 这些异常将记录并标记我们.这种方法是经过深思熟虑和讨论的决定.

每个可能的异常都经过仔细考虑和选择,分为两类 – 适用于单个数据馈送但不会关闭服务(大多数)的类别,以及那些表明清晰编程或其他根本导致代码对所有数据馈送都没用.例如,如果我们无法写入事件日志,我们选择关闭服务,因为这是我们指示数据馈送未得到处理的主要机制.异常是在本地捕获的,因为本地环境是唯一可以继续做出决定的地方.此外,允许异常冒泡到更高级别(1)违反了抽象概念,并且(2)在工作线程中没有意义.

我对反对处理异常的人数感到惊讶.如果我每次尝试都有一角硬币.那么(例外){什么都不做}我知道,你会在永恒的剩余时间内获得镍币的变化.我认为死亡1如果对.NET框架的调用或您自己的代码抛出异常,您需要考虑会导致该异常发生的场景并明确决定如何处理它.我的代码在IO操作中捕获UnauthorizedExceptions,因为当我考虑如何发生这种情况时,我意识到添加新的datafeed目录需要授予服务帐户的权限(默认情况下它不会拥有它们).

我很欣赏这些建设性的意见……请不要批评简化的示例代码,并使用广泛的“这个糟透了”的画笔.代码不吸 – 它是防弹的,必然如此.

1如果Jon Skeet不同意,我只会说很长时间

解决方法

不,它不会烧你.即使将ContinueWith内联到正在运行新任务的当前线程(()=> new datafeedUploadHandler()..它也将获得锁定,例如没有死锁.
lock语句在内部使用Monitor类,它是可重入的.例如如果一个线程已经拥有/拥有锁,它可以多次获取一个锁. Multithreading and Locking (Thread-Safe operations)

而task.ContinueWith在ProcessModifieddatafeed完成之前启动的另一种情况就像你说的那样.运行ContinueWith的线程只需要等待获取锁定.

我真的会考虑做任务.ContinueWith和在锁之外的task.Start(),如果你审查它.并且可以根据您发布的代码进行操作.

您还应该查看System.Collections.Concurrent命名空间中的ConcurrentDictionary.这将使代码更容易,你不必自己管理锁定.你在这里进行某种比较交换/更新if(this.fileWatcherDictionary.ContainsNonNullKey(eventArgs.FullPath)).例如只有在词典中没有添加.这是一个原子操作.使用ConcurrentDictionary没有任何功能,但有一个AddOrUpdate方法.也许你可以使用这种方法重写它.根据您的代码,您可以安全地使用ConcurrentDictionary至少用于runningTaskDictionary

哦和TaskCreationoptions.LongRunning实际上是为每个任务创建一个新线程,这是一种昂贵的操作. Windows内部线程池在新的Windows版本中是智能的,并且正在动态调整.它会“看到”你正在做很多IO的东西,并会根据需要和实际产生新的线程.

问候

c# – 在Task.ContinueWith中嵌套锁定 – 安全,还是玩火?的更多相关文章

  1. iOS:核心图像和多线程应用程序

    我试图以最有效的方式运行一些核心图像过滤器.试图避免内存警告和崩溃,这是我在渲染大图像时得到的.我正在看Apple的核心图像编程指南.关于多线程,它说:“每个线程必须创建自己的CIFilter对象.否则,你的应用程序可能会出现意外行为.”这是什么意思?我实际上是试图在后台线程上运行我的过滤器,所以我可以在主线程上运行HUD(见下文).这在coreImage的上下文中是否有意义?

  2. ios – 多个NSPersistentStoreCoordinator实例可以连接到同一个底层SQLite持久性存储吗?

    我读过的关于在多个线程上使用CoreData的所有内容都讨论了使用共享单个NSPersistentStoreCoordinator的多个NSManagedobjectContext实例.这是理解的,我已经使它在一个应用程序中工作,该应用程序在主线程上使用CoreData来支持UI,并且具有可能需要一段时间才能运行的后台获取操作.问题是NSPersistentStoreCoordinator会对基础

  3. ios – XCode断点应该只挂起当前线程

    我需要调试多线程错误.因此,为了获得生成崩溃的条件,我需要在代码中的特定点停止一个线程,并等待另一个线程到达第二个断点.我现在遇到的问题是,如果一个线程遇到断点,则所有其他线程都被挂起.有没有办法只停止一个线程,让其他线程运行,直到它们到达第二个断点?)其他更有趣的选择:当你点击第一个断点时,你可以进入控制台并写入这应该在该断点处暂停当前上下文中的线程一小时.然后在Xcode中恢复执行.

  4. ios – 在后台线程中写入Realm后,主线程看不到更新的数据

    >清除数据库.>进行API调用以获取新数据.>将从API检索到的数据写入后台线程中的数据库中.>从主线程上的数据库中读取数据并渲染UI.在步骤4中,数据应该是最新数据,但我们没有看到任何数据.解决方法具有runloops的线程上的Realm实例,例如主线程,updatetothelatestversionofthedataintheRealmfile,因为通知被发布到其线程的runloop.在后台

  5. ios – NSURLConnectionLoader线程中的奇怪崩溃

    我们开始看到我们的应用启动时发生的崩溃.我无法重现它,它只发生在少数用户身上.例外情况是:异常类型:EXC_BAD_ACCESS代码:KERN_INVALID_ADDRESS位于0x3250974659崩溃发生在名为com.apple.NSURLConnectionLoader的线程中在调用时–[NSBlockOperationmain]这是该线程的堆栈跟踪:非常感谢任何帮助,以了解可能导致这种崩

  6. ios – 合并子上下文时的NSObjectInaccessbileExceptions

    我尝试手动重现,但失败了.是否有其他可能发生这种情况的情况,是否有处理此类问题的提示?解决方法在创建子上下文时,您可以尝试使用以下行:

  7. ios – 从后台线程调用UIKit时发出警告

    你如何处理项目中的这个问题?

  8. ios – 在SpriteKit中,touchesBegan在与SKScene更新方法相同的线程中运行吗?

    在这里的Apple文档AdvancedSceneProcessing中,它描述了更新方法以及场景的呈现方式,但没有提到何时处理输入.目前尚不清楚它是否与渲染循环位于同一个线程中,或者它是否与它并发.如果我有一个对象,我从SKScene更新方法和touchesBegan方法(在这种情况下是SKSpriteNode)更新,我是否要担心同步对我的对象的两次访问?解决方法所以几天后没有回答我设置了一些实验

  9. ios – 在后台获取中加载UIWebView

    )那么,有一种方法可以在后台加载UIWebView吗?解决方法如果要从用户界面更新元素,则必须在应用程序的主队列(或线程)中访问它们.我建议您在后台继续获取所需的数据,但是当需要更新UIWebView时,请在主线程中进行.你可以这样做:或者您可以创建一个方法来更新UIWebView上的数据,并使用以下方法从后台线程调用它:这将确保您从正确的线程访问UIWebView.希望这可以帮助.

  10. ios – 何时使用Semaphore而不是Dispatch Group?

    我会假设我知道如何使用DispatchGroup,为了解问题,我尝试过:结果–预期–是:为了使用信号量,我实现了:并在viewDidLoad方法中调用它.结果是:从概念上讲,dispachGroup和Semaphore都有同样的目的.老实说,我不熟悉:什么时候使用信号量,尤其是在与dispachGroup合作时–可能–处理问题.我错过了什么部分?

随机推荐

  1. c# – (wpf)Application.Current.Resources vs FindResource

    所以,我正在使用C#中的WPF创建一个GUI.它看起来像这样:它现在还没有完成.这两行是我尝试制作一种数据表,它们在XAML中是硬编码的.现在,我正在C#中实现添加新的水果按钮功能.我在XAML中有以下样式来控制行的背景图像应该是什么样子:因此,在代码中,我为每列col0,col1和col2创建一个图像,如果我使用以下代码,它添加了一个如下所示的新行:如你所见,它不太正确……为什么一个似乎忽略了一些属性而另一个没有?

  2. c# – 绑定DataGridTemplateColumn

    似乎我已经打了个墙,试图在DataGrid上使用DataTemplates.我想要做的是使用一个模板来显示每个单元格的两行文本.但是似乎无法以任何方式绑定列.以下代码希望显示我想做的事情.注意每个列的绑定:模板列没有这样的东西,因此,这个xaml不可能工作.我注定要将整个DataTemplate复制到每个列,只是对每个副本都有不同的约束?解决方法我不完全确定你想要做什么,但如果您需要获取整行的DataContext,可以使用RelativeSource绑定来移动视觉树.像这样:

  3. c# – 学习设计模式的资源

    最近我来到了这个设计模式的概念,并对此感到非常热情.你能建议一些帮助我深入设计模式的资源吗?

  4. c# – 是否有支持嵌入HTML页面的跨操作系统GUI框架?

    我想开发一个桌面应用程序来使用跨系统,是否有一个GUI框架,允许我为所有3个平台编写一次代码,并具有完全可脚本化的嵌入式Web组件?我需要它有一个API来在应用程序和网页之间进行交流.我知道C#,JavaScript和一些python.解决方法Qt有这样的事情QWebView.

  5. c# – 通过字符串在对象图中查找属性

    我试图使用任意字符串访问嵌套类结构的各个部分.给出以下(设计的)类:我想要从Person对象的一个实例的“PersonsAddress.HousePhone.Number”获取对象.目前我正在使用反思来做一些简单的递归查找,但是我希望有一些忍者有更好的想法.作为参考,这里是我开发的(crappy)方法:解决方法您可以简单地使用标准的.NETDataBinder.EvalMethod,像这样:

  6. c# – 文件下载后更新页面

    FamilyID=0a391abd-25c1-4fc0-919f-b21f31ab88b7&displaylang=en&pf=true它呈现该页面,然后使用以下元刷新标签来实际向用户提供要下载的文件:你可能需要在你的应用程序中做类似的事情.但是,如果您真的有兴趣在文件完全下载后执行某些操作,那么您的运气不佳,因为没有任何事件可以与浏览器进行通信.执行此操作的唯一方法是上传附件时使用的AJAXupload.

  7. c# – 如何在每个机器应用程序中实现单个实例?

    我必须限制我的.net4WPF应用程序,以便每台机器只能运行一次.请注意,我说每个机器,而不是每个会话.我使用一个简单的互斥体实现单实例应用程序,直到现在,但不幸的是,这样一个互斥是每个会话.有没有办法创建机器互连,还是有其他解决方案来实现每个机器应用程序的单个实例?

  8. c# – WCF和多个主机头

    我的雇主网站有多个主机名,都是同一个服务器,我们只是显示不同的皮肤来进行品牌宣传.不幸的是,在这种情况下,WCF似乎不能很好地工作.我试过overridingthedefaulthostwithacustomhostfactory.这不是一个可以接受的解决方案,因为它需要从所有主机工作,而不仅仅是1.我也看过thisblogpost,但是我无法让它工作,或者不是为了解决我的问题.我得到的错误是“这

  9. c# – ASP.NET MVC模型绑定与表单元素名称中的虚线

    我一直在搜索互联网,试图找到一种方式来容纳我的表单元素的破折号到ASP.NET的控制器在MVC2,3或甚至4中的默认模型绑定行为.作为一名前端开发人员,我更喜欢在我的CSS中使用camelCase或下划线进行破折号.在我的标记中,我想要做的是这样的:在控制器中,我会传入一个C#对象,看起来像这样:有没有办法通过一些正则表达式或其他行为来扩展Controller类来适应这种情况?我讨厌这样的事实,我必须这样做:甚至这个:思考?

  10. c# – 用户界面设计工具

    我正在寻找一个用户界面设计工具来显示文档中可能的GUI.我不能生成代码.我知道MicrosoftVisio提供了一个功能.但有什么办法吗?您使用哪种软件可视化GUI?

返回
顶部