3

我用Pcap.Net交通监控,我需要它,直到用户请求取消接收数据包。创建监视任务这样(简化):中止任务包含永无止境的库法(无检查取消申请的能力)

var task1 = Task.Run(() => { communicator.ReceivePackets(0, PacketHandlerCallback); } /*, token*/); 

这里0说的ReceivePackets执行永远不会结束,PacketHandlerCallback是每个接收的数据包将被执行的方法。 ReceivePackets是同步的并且不支持取消。一般在我的问题它可能是任何其他无尽的同步方法,我们不能编辑代码

的问题是如何制止这种方法执行?

  • 刚好路过取消标记的任务没有帮助,因为我们也应明确检查要求取消,E。 G。通过调用token.throwIfCancellationRequested()

  • 将令牌传递给回调方法也不是一个解决方案,因为直到接收到新数据包时才会调用此方法,但是我希望在取消后立即停止我的任务。

  • 使用BackgroundWorker会导致相同的问题,因为我们应该检查CancellationPending

  • 创建task2定期检查取消请求,然后写var task = Task.WhenAny(task1, task2)没有帮助,因为ReceivePackets仍将执行

我应该使用Thread.Abort()或许有其他优雅的解决方案?
有关于TPL的类似问题,所以我找不到任何简单而有用的答案。

+0

你可能要考虑设置'communicator.NonBlocking = TRUE;然后重写你的代码在非阻塞模式下使用'communicator.ReceiveSomePackets'代替,那么你不必担心代码被挂起,你可以在想要清理所有东西的时候处理通信器。 –

+0

@斯科特很好的建议,谢谢。我知道这不是什么问题,但现在正是我需要的。请你确认一下,如果我写'while(true){communicator.ReceiveSomePackets(/ * args * /); token.throwIfCancellationRequested(); }'对于非阻塞通信器我不会丢失在取消请求检查期间可以接收的数据包? –

+0

以前从未使用过图书馆,我只查了一下资料来源,看到了房产和房产票据。 –

回答

1

通常Thread.Abort真的不应该作为过时非常危险和方法。然而,你的情况看起来,你必须杀死线程/进程停止无限的方法。

我建议你避免你的任何线程中止,因为这会导致你的系统不稳定,因为中止线程不就能够正确地清理资源。您可以run your method in new AppDomain,并在取消请求的情况下卸载该域名。另外,正如斯科特所说的,单独的Process也是一个解决方案。

当且仅当,所以某种原因,这是不是一种选择适合你,你可以subscribe for cancellation of your token with Thread.CurrentThread.Abort,但如果我是你,我会避免使用此选项,就像我可以。

此外,您可以创建一个task from cancellation token并使用WhenAll异步等待取消。

1

在您不能取消比Thread.Abort的好得多的解决方案的情况下是将不可撤销的代码到一个单独的进程,你可以杀死。

这给你保证释放所有线程的资源,因为操作系统将在进程退出时释放任何持有的非托管操作系统资源(如句柄),如果中止线程或者如果使用单独关闭AppDomain。

当你编写了第二个过程时,你可以使用类似WCF over named pipes的东西,这样你就可以与外部过程交互,就像你在过程中的任何其他正常功能一样。

1

PacketCommunicator.Break()方法。

从文档代码:

/// <summary> 
/// Set a flag that will force ReceiveSomePackets(), ReceivePackets() or ReceiveStatistics() to return rather than looping. 
/// They will return the number of packets/statistics that have been processed so far, with return value BreakLoop. 
/// <seealso cref="ReceiveSomePackets"/> 
/// <seealso cref="ReceivePackets"/> 
/// <seealso cref="ReceiveStatistics(int, HandleStatistics)"/> 
/// </summary> 
/// <remarks> 
/// <list type="bullet"> 
///  <item>This routine is safe to use inside a signal handler on UNIX or a console control handler on Windows, as it merely sets a flag that is checked within the loop.</item> 
///  <item>The flag is checked in loops reading packets from the OS - a signal by itself will not necessarily terminate those loops - as well as in loops processing a set of packets/statistics returned by the OS.</item> 
///  <item>Note that if you are catching signals on UNIX systems that support restarting system calls after a signal, and calling Break() in the signal handler, you must specify, when catching those signals, that system calls should NOT be restarted by that signal. Otherwise, if the signal interrupted a call reading packets in a live capture, when your signal handler returns after calling Break(), the call will be restarted, and the loop will not terminate until more packets arrive and the call completes.</item> 
///  <item>ReceivePacket() will, on some platforms, loop reading packets from the OS; that loop will not necessarily be terminated by a signal, so Break() should be used to terminate packet processing even if ReceivePacket() is being used.</item> 
///  <item>Break() does not guarantee that no further packets/statistics will be processed by ReceiveSomePackets(), ReceivePackets() or ReceiveStatistics() after it is called; at most one more packet might be processed.</item> 
///  <item>If BreakLoop is returned from ReceiveSomePackets(), ReceivePackets() or ReceiveStatistics(), the flag is cleared, so a subsequent call will resume reading packets. If a different return value is returned, the flag is not cleared, so a subsequent call will return BreakLoop and clear the flag.</item> 
/// </list> 
/// </remarks>