我从我读过的关于该主题的大量文章中了解到 Thread.Abort() 是邪恶的,所以我目前正在删除我的 abort's 以便以更清洁的方式替换它;在比较了 stackoverflow 上人们的用户策略之后,然后阅读了 "How to: Create and Terminate Threads (C# Programming Guide) "来自 MSDN,两者都说明了一种非常相同的方法——即使用 volatile bool方法检查策略,这很好,但我还有一些问题......
对我来说,最突出的一点是,如果您没有一个简单的工作进程,它只是运行一个循环处理代码怎么办?例如对我来说,我的进程是一个后台文件上传进程,我实际上循环遍历每个文件,所以这就是我可以添加我的 while (!_shouldStop)在覆盖我每次循环迭代的顶部,但我有更多的业务流程发生在它到达下一次循环迭代之前,我希望这个取消过程快速;不要告诉我我需要在整个工作函数中每 4-5 行向下撒一次这些 while 循环?!
我真的希望有更好的方法,有人可以告诉我这是否确实是正确的[且唯一的?] 方法,或者他们过去使用的策略来实现我所追求的目标。
谢谢帮。
进一步阅读:All these SO responses假设工作线程将循环。这对我来说并不舒服。如果是线性但及时的后台操作呢?
最佳答案
不幸的是,可能没有更好的选择。这实际上取决于您的具体情况。这个想法是在安全点优雅地停止线程。这就是为什么Thread.Abort的关键所在不好;因为它不能保证发生在安全点。通过在代码中添加停止机制,您可以有效地手动定义安全点。这称为合作取消。基本上有 4 种广泛的机制可以做到这一点。您可以选择最适合您情况的一种。
轮询停止标志
你已经提到了这个方法。这是一个很常见的。在算法中的安全点定期检查标志,并在收到信号时退出。标准方法是标记变量 volatile .如果这是不可能的或不方便的,那么您可以使用 lock .请记住,您不能将局部变量标记为 volatile因此,例如,如果 lambda 表达式通过闭包捕获它,那么您将不得不采用不同的方法来创建所需的内存屏障。对于这种方法,无需多说。
使用 TPL 中的新取消机制
这类似于轮询停止标志,不同之处在于它使用 TPL 中的新取消数据结构。它仍然基于合作取消模式。你需要得到一个 CancellationToken和定期检查IsCancellationRequested .要请求取消,您可以调用 Cancel在 CancellationTokenSource最初提供 token 的那个。您可以使用新的取消机制做很多事情。您可以阅读更多关于 here .
使用等待句柄
如果您的工作线程在正常操作期间需要等待特定时间间隔或信号,则此方法很有用。您可以 Set ManualResetEvent ,例如,让线程知道是时候停止了。您可以使用 WaitOne 测试事件返回 bool 的函数指示事件是否已发出信号。 WaitOne接受一个参数,该参数指定如果在该时间内未发出事件信号,则等待调用返回的时间。您可以使用此技术代替 Thread.Sleep并同时得到停止指示。如果还有其他 WaitHandle 也很有用线程可能必须等待的实例。您可以拨打WaitHandle.WaitAny在一次调用中等待任何事件(包括停止事件)。使用事件比调用 Thread.Interrupt 更好因为您可以更好地控制程序流程(Thread.Interrupt 抛出异常,因此您必须策略性地放置 try-catch 块以执行任何必要的清理)。
专业场景
有几种一次性方案具有非常专业的停止机制。将它们全部列举出来绝对超出了这个答案的范围(更不用说这几乎是不可能的)。我在这里的意思的一个很好的例子是 Socket类(class)。如果线程在调用 Send 时被阻塞或 Receive然后拨打 Close将在有效解除阻塞的任何阻塞调用上中断套接字。我确信 BCL 中还有其他几个区域可以使用类似的技术来解除线程阻塞。
通过 Thread.Interrupt 中断线程
这里的优点是它很简单,您不必真正专注于在代码中添加任何东西。缺点是您几乎无法控制算法中安全点的位置。原因是因为Thread.Interrupt通过在 jar 装 BCL 阻塞调用之一中注入(inject)异常来工作。其中包括 Thread.Sleep , WaitHandle.WaitOne , Thread.Join等。所以你必须明智地放置它们。然而,大多数时候算法决定了它们去哪里,这通常很好,特别是如果你的算法大部分时间都花在这些阻塞调用之一上。如果您的算法不使用 BCL 中的阻塞调用之一,则此方法对您不起作用。这里的理论是ThreadInterruptException仅从 .NET 等待调用生成,因此它可能处于安全点。至少您知道该线程不能处于非托管代码中,也不能退出临界区而使悬空锁处于已获取状态。尽管这比 Thread.Abort 侵入性小我仍然不鼓励使用它,因为哪个调用响应它并不明显,而且许多开发人员将不熟悉它的细微差别。
关于c# - 关于在 .NET 中干净地终止线程的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3632149/
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha