【问题标题】:Detecting when a BackgroundWorker has its job done? Depending on circumstances, it needs to be rerun检测 BackgroundWorker 何时完成工作?视情况而定,需要重新运行
【发布时间】:2018-04-03 07:28:39
【问题描述】:

我的班级监视传入文件的目录。它确实使用FileSystemWatcher 对象执行此操作,仅监视FSWCreated 事件。

Created 事件中,我开始了一个可能很耗时的过程(需要文件反序列化,使用我的类向客户端发送一个事件,其中可能会发生各种事情)。因此,我启动了一个 BackgroundWorker 对象来完成所有这些工作,最终将接收到的文件删除。

但是,在所有这些工作期间,可能会出现新文件。在Created 事件中,我检查BGW 是否仍然忙,如果是,我只需将完全限定名称存储在队列中以供以后使用。

Public Sub New(Path As String)
    FSM = New FileSystemWatcher
    With FSW
        .Path = Path
        AddHandler .Created, AddressOf pFileArrived
    End With

    BGW = New BackgroundWorker
    With BGW
        .WorkerReportsProgress = False
        .WorkerSupportsCancellation = False
        AddHandler .DoWork, AddressOf BGW_DoWork
        AddHandler .RunWorkerCompleted,
            AddressOf BGW_RunWorkerCompleted
    End With
End Sub

Private Sub pFileArrived(sender As Object, e As FileSystemEventArgs)
    pNotifyClient(e.FullPath)
End Sub

Private Sub pNotifyClient(sFullPath As String)
    If Not BGW.IsBusy Then
        BGW.RunWorkerAsync(sFullPath)
    Else
        MyQueue.Enqueue(sFullPath)
    End If
End Sub

Private Sub BGW_DoWork(ByVal sender As Object,
    ByVal e As DoWorkEventArgs)

    '...
End Sub

但是我怎样才能知道BGW 何时完成?

我知道,有 RunWorkerCompleted 事件。然而,这个事件是从一个仍然存在的真实的BGW 实例触发的,所以我不能继续简单地从事件处理程序中再次调用它。

Private Sub BGW_RunWorkerCompleted(sender As Object,
    e As RunWorkerCompletedEventArgs)

    'This won't work.
    If MyQueue.Count > 0 Then
        BGW.RunWorkerAsync(MyQueue.Dequeue)
    End If
End Sub

做这些事情的正确方法是什么?初始化计时器确实浮现在脑海中,但它似乎并不正确。 (我应该给它多少时间?我应该循环到BGW 线程的结尾吗?)

或者我应该考虑其他方法而不是调用 BGW?

【问题讨论】:

  • 与其尝试计算 BGW 何时完成以便重新开始,为什么不让它完成呢?为此,您需要将DoWork 事件处理程序的内容放在DoWhile 循环中,并且仅在队列为空时退出该循环。 FSW 在循环结束和IsBusy 属性被设置回False 之间添加到队列的可能性很小。不过这是一个很小的机会,无论如何,该项目将在下次处理。如果你真的很热衷,你也可以使用一些线程同步来完全阻止它。
  • @jmcilhinney,这是我最初的尝试,我放弃了正是因为这个微小的(是吗?)机会:距离下一个 FSW_Create 事件可能还有几分钟,但客户端通知延迟超过几秒钟是不能容忍的。您会采用哪种同步技术?我认为在我的情况下我不能使用AutoResetEvent,正如 Tanveer Badar 下面所建议的那样,请参阅那里的评论。
  • 非常无法预测您可以在什么时候对收到通知的文件执行某些操作。几乎永远不会在您收到通知的确切时间,因为该文件仍在被进程修改。当它关闭文件是不可知的。您需要一个带有线程安全队列的生产者/消费者场景,您可以在其中填充字符串。消费者可以是定期尝试清空队列的 BGW。因此,计时器是正确的方法。
  • @HansPassant,我会采用这种方法,谢谢。我如何确定该文件是否可访问?尝试在 Try-Catch 块中打开它是唯一(浪费)的可能性吗?
  • 你已经知道该怎么做了。没有 File.IsLocked() 方法,它不是原子的。浪费在对文件系统执行任何操作的代码中不是问题,这样的代码总是以毫秒的速度运行。

标签: vb.net multithreading asynchronous backgroundworker filesystemwatcher


【解决方案1】:

如果你想从轨道上解决这个问题,把AutoResetEvent(false)放在某个地方,你的BGW的最后一个任务应该是evt.Set(),你的主线程可以做evt.WaitOne(0)来查询状态。如果有可能同时运行多个 BGW,则需要一些数据结构来跟踪哪个 ARE 与哪个 BGW 相关联。

更大的投资将转向纯粹的生产者-消费者设计,其中涉及一个队列(您已经在一个表单中拥有)和消费者线程来使工作项出列并处理它们。

【讨论】:

  • 问题是,主线程没有在循环中执行或这样:我没有有意义的地方可以用WaitOne(0)查询后台线程的状态。 FSW_Create 事件处理程序告诉BGW 开始,然后它会简单地等待下一个FSW_Create 事件,这可能需要几分钟。运行多个 BGW 实例并不是一个真正的选择,因为传入文件的顺序很重要:它们需要按顺序处理。
猜你喜欢
  • 2017-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多