C# 4.0 懒惰<;T>;仅限LazyThreadSafeMode.PublicationOnly和IDisposable
今天我在玩LazyC# 4.0 懒惰<;T>;仅限LazyThreadSafeMode.PublicationOnly和IDisposable,c#-4.0,idisposable,lazythreadsafetymode,C# 4.0,Idisposable,Lazythreadsafetymode,今天我在玩Lazy,发现了一个有趣的案例(在我看来) 仅限出版物: 当多个线程试图同时初始化一个惰性实例时,所有线程都可以运行初始化方法。。。由竞争线程创建的任何T实例都将被丢弃 如果我们查看Lazy.LazyInitValue()的代码,我们会发现没有检查IDisposable实现,解析可能会泄漏到这里: case LazyThreadSafetyMode.PublicationOnly: boxed = this.CreateValue(); if (I
,发现了一个有趣的案例(在我看来)
- 仅限出版物:
当多个线程试图同时初始化一个惰性实例时,所有线程都可以运行初始化方法。。。由竞争线程创建的任何T实例都将被丢弃
如果我们查看Lazy
.LazyInitValue()的代码,我们会发现没有检查IDisposable实现,解析可能会泄漏到这里:case LazyThreadSafetyMode.PublicationOnly: boxed = this.CreateValue(); if (Interlocked.CompareExchange(ref this.m_boxed, boxed, null) != null) { //* boxed.Dispose(); -> see below. boxed = (Boxed<T>) this.m_boxed; } break;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace LazyInit {
class DisposableClass : IDisposable {
private IntPtr _nativeResource = Marshal.AllocHGlobal(100);
private System.IO.MemoryStream _managedResource = new System.IO.MemoryStream();
public string ThreadName { get; set; }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposableClass() {
Console.WriteLine("Disposing object created on thread " + this.ThreadName);
Dispose(false);
}
private void Dispose(bool disposing) {
if (disposing) {
// free managed resources
if (_managedResource != null) {
_managedResource.Dispose();
_managedResource = null;
}
}
// free native resources if there are any.
if (_nativeResource != IntPtr.Zero) {
Marshal.FreeHGlobal(_nativeResource);
_nativeResource = IntPtr.Zero;
}
}
}
static class Program {
private static Lazy<DisposableClass> _lazy;
[STAThread]
static void Main() {
List<Thread> t1 = new List<Thread>();
for (int u = 2, i = 0; i <= u; i++)
t1.Add(new Thread(new ThreadStart(InitializeLazyClass)) { Name = i.ToString() });
t1.ForEach(t => t.Start());
t1.ForEach(t => t.Join());
Console.WriteLine("The winning thread was " + _lazy.Value.ThreadName);
Console.WriteLine("Garbage collecting...");
GC.Collect();
Thread.Sleep(2000);
Console.WriteLine("Application exiting...");
}
static void InitializeLazyClass() {
_lazy = new Lazy<DisposableClass>(LazyThreadSafetyMode.PublicationOnly);
_lazy.Value.ThreadName = Thread.CurrentThread.Name;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Runtime.InteropServices;
使用系统线程;
名称空间LazyInit{
类别可处置类别:IDisposable{
私有IntPtr _nativeResource=Marshal.AllocHGlobal(100);
private System.IO.MemoryStream _managedResource=new System.IO.MemoryStream();
公共字符串ThreadName{get;set;}
公共空间处置(){
处置(真实);
总干事(本);
}
~DisposableClass(){
WriteLine(“正在处理线程上创建的对象”+this.ThreadName);
处置(虚假);
}
私有无效处置(bool处置){
如果(处置){
//免费管理的资源
如果(_managedResource!=null){
_managedResource.Dispose();
_managedResource=null;
}
}
//免费本地资源(如果有)。
如果(_nativeResource!=IntPtr.Zero){
自由全球元帅(_nativeResource);
_nativeResource=IntPtr.Zero;
}
}
}
静态类程序{
私有静态惰性(u Lazy);;
[状态线程]
静态void Main(){
列表t1=新列表();
对于(intu=2,i=0;it.Start());
t1.ForEach(t=>t.Join());
WriteLine(“获胜的线程是”+\u lazy.Value.ThreadName);
控制台.WriteLine(“垃圾收集…”);
GC.Collect();
《睡眠》(2000年);
WriteLine(“应用程序正在退出…”);
}
静态void InitializeLazyClass(){
_lazy=新的lazy(仅LazyThreadSafetyMode.PublicationOnly);
_lazy.Value.ThreadName=Thread.CurrentThread.Name;
}
}
}
它使用LazyThreadSafetyMode.PublicationOnly
,创建三个线程,每个线程实例化Lazy
,然后退出
输出如下所示:
获胜的线程是1
垃圾收集
正在处理线程2上创建的对象
正在处理线程0上创建的对象
应用程序正在退出
正在处理线程1上创建的对象
如问题中所述,Lazy.LazyInitValue()
不检查IDisposable,并且没有显式调用Dispose()
,但仍然最终处理了所有三个对象;处理两个对象是因为它们超出范围并被垃圾收集,第三个对象是在应用程序退出时处理的。发生这种情况的原因是,我们正在使用销毁所有托管对象时调用的析构函数/终结器,并反过来使用它来确保释放非托管资源
至于第二个问题,为什么没有设立可识别的支票,大家都在猜测。也许他们没有设想在实例化时分配非托管资源
进一步阅读:
有关如何正确实现IDisposable的更多信息,请查看MSDN(我的示例有一半来自MSDN)
此外,还有一篇优秀的SO文章,它给出了我所见过的最好的解释,为什么IDisposable应该以这种方式实现。这在.NET上被忽略了,这就是为什么我同时提供和。顺便说一下,我的计算机模拟了这种行为(请看代码的末尾)。
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace LazyInit {
class DisposableClass : IDisposable {
private IntPtr _nativeResource = Marshal.AllocHGlobal(100);
private System.IO.MemoryStream _managedResource = new System.IO.MemoryStream();
public string ThreadName { get; set; }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposableClass() {
Console.WriteLine("Disposing object created on thread " + this.ThreadName);
Dispose(false);
}
private void Dispose(bool disposing) {
if (disposing) {
// free managed resources
if (_managedResource != null) {
_managedResource.Dispose();
_managedResource = null;
}
}
// free native resources if there are any.
if (_nativeResource != IntPtr.Zero) {
Marshal.FreeHGlobal(_nativeResource);
_nativeResource = IntPtr.Zero;
}
}
}
static class Program {
private static Lazy<DisposableClass> _lazy;
[STAThread]
static void Main() {
List<Thread> t1 = new List<Thread>();
for (int u = 2, i = 0; i <= u; i++)
t1.Add(new Thread(new ThreadStart(InitializeLazyClass)) { Name = i.ToString() });
t1.ForEach(t => t.Start());
t1.ForEach(t => t.Join());
Console.WriteLine("The winning thread was " + _lazy.Value.ThreadName);
Console.WriteLine("Garbage collecting...");
GC.Collect();
Thread.Sleep(2000);
Console.WriteLine("Application exiting...");
}
static void InitializeLazyClass() {
_lazy = new Lazy<DisposableClass>(LazyThreadSafetyMode.PublicationOnly);
_lazy.Value.ThreadName = Thread.CurrentThread.Name;
}
}
}