我有一个名为BackgroundWorker有一个线程不断运行的类.要关闭此线程,stop需要命名为的实例变量true.
为了确保在使用完类时释放线程,我添加IDisposable了一个调用的终结器Dispose().假设stop = true确实导致此线程退出,这个sippet是否正确?Dispose从终结器调用是对的,对吧?
终结者应该总是调用,Dispose如果object继承IDisposable,对吧?
/// <summary>
/// Force the background thread to exit.
/// </summary>
public void Dispose()
{
lock (this.locker)
{
this.stop = true;
}
}
~BackgroundWorker()
{
this.Dispose();
}
Run Code Online (Sandbox Code Playgroud) 在.net中写下以下内容是否合法?
public class A
{
public int i = 0;
~A()
{
Aref = this;
}
}
public static A Aref;
static void Main(string[] args)
{
Aref = new A();
int gen = GC.GetGeneration(Aref);
Aref = null;
GC.Collect(gen, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
Console.WriteLine(Aref.i);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
它工作并按预期将"0"写入控制台,但我想知道它是否保证始终有效.
有人知道幕后发生了什么吗?
请参阅MSDN中的代码示例:(http://msdn.microsoft.com/en-us/library/b1yfkh5e ( v=VS.100 ) .aspx)
// Design pattern for a base class.
public class Base: IDisposable
{
private bool disposed = false;
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
disposed = true;
}
}
// Use C# destructor syntax for finalization code.
~Base()
{ …Run Code Online (Sandbox Code Playgroud) 据我所知,如果你有一个具有IDisposable的成员m的A类,A应该实现IDisposable,它应该在其中调用m.Dispose().
我找不到令人满意的理由,为什么会这样.
我理解规则如果你有非托管资源,你应该提供一个终结器和IDisposable,这样如果用户没有显式调用Dispose,终结器仍然会在GC期间清理.
但是,根据该规则,您似乎不需要具有此问题的规则.例如...
如果我有课:
class MyImage{
private Image _img;
... }
Run Code Online (Sandbox Code Playgroud)
公约规定我应该有MyImage : IDisposable.但是如果Image遵循惯例并实现了终结器而我并不关心资源的及时发布,那有什么意义呢?
UPDATE
我在这里找到了一个很好的讨论.
在聊天的讨论过程中,我编写了这个控制台应用程序.
using System;
class Program
{
static void Main(string[] args)
{
CreateClass();
Console.Write("Collecting... ");
GC.Collect();
Console.WriteLine("Done");
}
static void CreateClass()
{
SomeClass c = new SomeClass();
}
}
class SomeClass
{
~SomeClass()
{
throw new Exception();
}
}
Run Code Online (Sandbox Code Playgroud)
Collecting... Done
Unhandled Exception: System.Exception: Exception of type 'System.Exception' was
thrown.
at SomeClass.Finalize()
Run Code Online (Sandbox Code Playgroud)
我本来以为应用程序在 Done打印前会崩溃.
我不太关心如何制作它.我的问题是,为什么不呢?
在Ruby中,我有一个DAO类,它通过一个类来扩展,这使得管理连接变得更容易,这个类由表示和操作DB中的数据的类扩展,该类由另一个类进一步扩展.使用动物比喻它看起来像这样:
class Animal
...
end
class Mammal < Animal
...
end
class Feline < Mammal
...
end
class Cat < Feline
...
end
class Lion < Cat
...
end
...
Run Code Online (Sandbox Code Playgroud)
在PHP中,有一种__destruct方法可以在销毁/删除类时运行.如果该类扩展另一个类,您只需添加parent::__destruct()到类的__destruct方法,如下所示:
public function __destruct() {
// Clean up code for this class here
...
// Execute clean up code for Parent class
parent::__destruct();
}
Run Code Online (Sandbox Code Playgroud)
我可以为所有类提供类似的方法,除了Animal.由于它没有扩展任何内容,因此该parent::__destruct();行不再有效.
但是,据我所知,Ruby没有像这样的方法用于它的对象.可以设置终结器,但我决定cleanup只要我想要销毁/删除一个类就可以调用一个方法.这会照顾我在设置课程之前需要做的任何事情nil.
这引发了一个新问题.如果方法总是被命名cleanup并且我打电话lion_instance.cleanup,我认为它调用了Lion#cleanup.然后如何让它cleanup在课堂上调用Cat …
我在c中有一些函数,我会在.net应用程序中使用它.为此,我用C++/cli编写了一个Wrapper类.
在c接口中是一个回调函数,并将其包装在.net委托中.
但是我应该如何释放回调gcHandle的非托管资源呢?是否允许在终结器中从GCHandle调用IsAllocated和Free?因为它是一个托管资源,并且gc已经可以释放它了吗?
这是c接口的代码:
// C functions
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*my_native_callback)(const uint8_t buffer[], uint32_t buffer_len);
void register_callback(my_native_callback c, uint32_t* id);
void remove_callback(uint32_t id);
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
这里是.net包装器:
// .net wrapper (c++/cli)
public ref class MyWrapper
{
public:
MyWrapper()
{
RegisterCallback();
}
// Destructor.
~MyWrapper()
{
this->!MyWrapper();
}
protected:
// Finalizer.
!MyWrapper()
{
RemoveCallback(); // <- Is this safe?
// ... release other unmanaged ressorces
}
private:
void RegisterCallback()
{
uint32_t id = 0;
callbackDelegate_ …Run Code Online (Sandbox Code Playgroud) 所以我想的是一个类的实例,我想要一个线程在类的生命周期中运行,但是当调用类的进程不再运行时终止.这不是父线程终止子进程的情况,而是单个旋转(在等待循环中)线程正常退出而不保留资源等.
我认为在C++中,你可以告诉线程使用析构函数中的volatile bool来终止,但是在C#中,〜不是析构函数,它是终结器.我无法使用终结器成功终止线程.也许我错过了一些东西.我知道更好的做法是让所有线程死于自然死亡而不发出信号终止,但每次我需要做某事时产生一个线程效率都不高.是的我知道线程池,但我认为让一个侦听器线程响应对类的调用会更好,并且当类放在gc上时它会优雅地死掉.
真的诀窍是,我想,我可以知道,或者我怎么知道什么时候运行该线程的类首先放在gc上.IDisispos是我想要的吗?我这里没有使用任何非托管代码.
我有一个类型封装外部资源的键.一旦密钥丢失(共享它的所有值都超出范围),资源应该(隐式地)在下一个垃圾收集中释放,就像内存对常规值一样.
所以我正在寻找类似于OOP处理的东西,或者ForeignPtr,我只代表对外语对象的引用(尽管如果ForeignPtr能够正确和优雅地为此工作,知道如何也回答这个问题).
可能吗?如果是这样,怎么样?
StackOverflow上有几个关于如果我的对象管理其他实现的托管对象该怎么做的讨论System.IDisposable.
注意:下面我不是在讨论非托管代码.我完全理解清理非托管代码的重要性
大多数讨论都说如果你的对象拥有另一个实现的托管对象System.IDisposable,那么你也应该实现System.IDisposable,在这种情况下你应该调用Dispose()你的对象所持有的一次性对象.这是合乎逻辑的,因为您不知道您拥有的一次性对象是否使用非托管代码.你只知道另一个对象的创造者认为如果你Dispose不再需要这个对象就打电话会是明智的.
在社区维基编辑的StackOverflow中给出了对Disposable模式的一个非常好的解释:
很多时候,我在上面提到的链接中读到:
"你不知道两个对象被销毁的顺序.完全有可能在你的
Dispose()代码中,你试图摆脱的托管对象不再存在."
这让我感到困惑,因为我认为只要任何对象持有对象X的引用,那么对象X就不会也无法完成.
换句话说:只要我的对象持有对象XI的引用,就可以确定对象X没有最终确定.
如果这是真的,那么为什么会这样,如果我在完成之前持有对象的引用,我引用的对象已经完成了?
finalizer ×10
c# ×7
dispose ×4
idisposable ×3
destructor ×2
.net ×1
c++-cli ×1
delegates ×1
disposable ×1
ghc ×1
haskell ×1
ruby ×1