`
SilenceCliff
  • 浏览: 38334 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

多线程:从对象池(object pool)谈同步(syncronization) ——一个调试的问题

阅读更多
 

 

 

最近,刚看过Jeffry Richter的《Programming Application for Microsoft Windows 4th Edition》。眼下正看《C# Threading HandBook》。看了前三章,觉得很不错。觉得这本书很系统,自己也想把以前在一些书上看到的分散的东西彻底归整一遍。于是就从这里开个头吧。

 

还记得Jeffry Richter在《Appiled .NET Framework Programming》里的那个利用对象复苏设计的那个对象池吗?

且请容许我把代码在这里再贴一遍:

  1using System;
  2
  3using System.Collections;
  4
  5 
  6
  7namespace RichtersObjectPool
  8
  9
 10
 11       class Expensive
 12
 13       {
 14
 15              static Stack pool = new Stack();
 16
 17 
 18
 19              public static Expensive GetObjectFromPool()
 20
 21              {
 22
 23                     return (Expensive) pool.Pop();
 24
 25              }

 26
 27 
 28
 29              public static void ShutdownThePool()
 30
 31              {
 32
 33                     pool = null;
 34
 35              }

 36
 37 
 38
 39              public Expensive()
 40
 41              {
 42
 43                     //构造对象花费较长时间
 44
 45                     pool.Push(this);
 46
 47              }

 48
 49 
 50
 51              ~Expensive()
 52
 53              {
 54
 55                     if (pool != null)
 56
 57                     {
 58
 59                            GC.ReRegisterForFinalize(this);
 60
 61 
 62
 63                            pool.Push(this);
 64
 65                     }

 66
 67              }

 68
 69       }

 70
 71 
 72
 73       class App
 74
 75       {
 76
 77              [STAThread]
 78
 79              static void Main(string[] args)
 80
 81              {
 82
 83                     for (int i = 0; i < 10; i++)
 84
 85                            new Expensive();
 86
 87 
 88
 89                     //一些操作
 90
 91 
 92
 93                     Expensive e = Expensive.GetObjectFromPool();
 94
 95 
 96
 97                     //使用e
 98
 99 
100
101                     Expensive.ShutdownThePool();
102
103 
104
105              }

106
107       }

108
109}

110
111

 

现在且就这个object pool的实现我们来仔细看看。从整个设计来讲,Expensive类是一个多例模式。它通过一个聚集(静态的Stack)来管理该类的多个实例。从技巧上看,利用的是GC的对象复苏特性,即重载了Finalize方法的类(在C#中即是析构函数)在第一次垃圾收集时会经历一个终止化链表到终止化可达队列的转移的过程,如此从“死亡”既而又获得了“重生”。在这个实现中,在Finalize()中调用GC.ReRegisterForFinalize()是实现的关键。

但是,这个实现很大的限制了我们的应用。

我们被限制的应用有哪些呢?

Ø         这个object pool还不够智能化,每次我们在开始运行时,要自己手动构造一些对象,在应用程序退出时,还必须牢记要自己关闭object pool

Ø         栈中的元素只能增加,不能减少。即每当我再次构造一个对象压栈后,以前栈中的对象就必须多次调用GetObjectFromPool()才能得到。这个似乎不是很方便。

Ø         如果在程序运行期间构造了太多这样的对象,那么势必会耗费很多的资源,而实际上,可能只有在object pool中少数的对象正被使用或经常被使用。在某些场景下,我们需要一种对象生命周期的管理方法。

Ø         最后,最重要的是这个类不是线程安全的。

 

首先,我们可以考虑把管理多个对象的数据结构换做线程安全的哈希表:

 

在这里我要对HashTable多说两句。《Professinal C# 3rd Edition》里说的很清楚:

Ø         容量为素数的话,工作效率更高,且当散列表扩大容量重新分配内存的时候,总会选择一个素数作为其新的容量。

Ø         负载最大值越小,工作效率越高,但占据内存也越大。

Ø         HaskTable确定两个键AB是否相等的方式是调用A.Equals(B)。即必须确保如果A.Equals(B)true,则A.GetHashCode()B.GetHashCode()必须返回相同的散列。

 

上面的第三条也就是为什么编译器会以警告的方式强制必须同时重写Equals()GetHashCode()的原因。

 

对于System.Object来说,Equals()仅仅比较引用,而GetHashCode()会根据对象的地址返回一个散列。因此如果你的类这两个方法都不重载,将其运用到HashTable是可以正常工作的,但这样的类会受到“同一与相等”这个典型问题的限制。因此,最后自己为要用做键的类重写这两个方法。

 

此外,MS已经为String提供了一种虽然复杂、但很有效的散列算法。我们可以在自己的实现中利用这个算法。

 

最后,一般简单高效率的散列算法的设计是:获取字段,把它们与较大的素数相乘,再把结果加起来。

 

第二,既然我们选择了HashTable,那么用什么做主键,什么做值呢?

还记得,我们提过想把生命周期管理拿进来,而且希望对象的创建和销毁更自动化。鉴于此二者。我们可以把对象本身用做主键,而值用创建该对象时的时间来填充,每当被使用后,该值即立刻被更新。通过一个定时触发器根据对象的最近使用时间。来管理object pool中的对象。

 

第三,也就是关于对象的使用问题。其实,本质上讲,是一个有状态和无状态的问题。如果对象是有状态的,当我们从object pool取出一个对象后,该对象的状态不一定符合我们使用的要求。比如一个数据库连接,当我们从object pool取出时,它很有可能是关闭的。因此,这就很有必要在我们的取出操作中进行对象状态的验证。

 

第四,同步。除了谈到的使用线程安全的HashTable外,我们还有一些操作是需要原子特性的。我们可以把lock或者monitor施加在critical section上来得到保证。

 

说了这么多,我们来看看《C# Threading Handbook》中的这个更具使用价值的object pool的实现:

  

作为该书中的一个完整的例子。书中提供了一个数据库连接object pool的实现。代码如下:

using System;

using System.Data.SqlClient;

 

namespace WroxCS

{

     
public sealed class DBConnectionSingleton : ObjectPool

     
{

       
private DBConnectionSingleton() {}

 

       
public static readonly DBConnectionSingleton Instance =

           
new DBConnectionSingleton();

 

       
private static string _connectionString =

           
@"server=(local); Integrated Security=SSPI;database=northwind";

 

       
public static string ConnectionString

       
{

         
set

         
{

           _connectionString 
= value;

         }


         
get

         
{

           
return _connectionString;

         }


       }


 

       
protected override object Create()

       
{

         SqlConnection temp 
= new SqlConnection( ConnectionString);

         temp.Open();

         
return(temp);

       }


 

       
protected override bool Validate(object o)

       
{

         
try

         
{

           SqlConnection temp 
= (SqlConnection)o;

          
return(

            
! ((temp.State.Equals(System.Data.ConnectionState.Closed))));

         }


         
catch (SqlException)

         
{

           
return false;

         }


       }


 

       
protected override void Expire(object o)

分享到:
评论

相关推荐

    多线程:从对象池(objectpool)谈同步(syncronization)——一个调试的问题

    还记得JeffryRichter在《Appiled.NETFrameworkProgramming》里的那个利用对象复苏设计的那个对象池吗?且请容许我把代码在这里再贴一遍: 1using System; 2 3using System.Collections; 4 5 

    Windows 多线程API C++类的封装

    总的来说,"Windows 多线程API C++类的封装"是一个提高代码可读性和易用性的实践,它将底层的系统调用抽象成类方法,使得多线程编程更加直观,同时也便于代码的维护和扩展。通过这种方式,开发者可以更专注于业务...

    align_rgb.zip_MPI_in_mpi image processing

    从压缩包内的文件名"Align_RGB_planes.class"和"Align_RGB_planes.java"来看,这似乎是一个Java程序,可能是一个类,用于对RGB图像的三个颜色通道进行对齐或同步处理。在图像处理中,RGB图像的三个通道(红、绿、蓝...

    Thread Synchronization Library for .Net-开源

    在.NET框架中,线程同步是多线程编程的一个关键概念,它确保了多个线程在访问共享资源时能够按照预定的顺序或者互斥方式进行,从而避免数据竞争和不一致的状态。开源的线程同步库为开发者提供了丰富的工具和机制,以...

    CUDA_CUDA简介_

    在CUDA体系结构中,GPU被设计为一个高度并行的处理器,包含大量的流处理器(Streaming Multiprocessors, SMs),每个SM又由多个线程块(Thread Blocks)组成,线程块内有多个线程(Threads)。这种层次化的并行模型...

    移动全网规划与建设-实训:非独立组网无线站点数据配置.docx

    Option 3X是一种5G NSA部署方式,其中5G NR(New Radio)通过LTE eNodeB与核心网连接,形成一个E-UTRA-NR Dual Connectivity (EN-DC)场景。在这样的架构下,5G NR作为辅站(Secondary Cell, SCell),而4G LTE作为...

    exynos_drm_fimc.rar_fimc_memory

    4. **中断处理(Interrupt Handling)**:当DMA传输完成或者FIMC处理完一个图像帧后,中断会被触发。驱动程序需要正确地注册中断处理程序来响应这些事件。 5. **内存管理策略**:包括如何分配连续的物理内存供DMA...

    等教育自学考试计算机网络技术试题参照.pdf

    同步时分多路复用,将多个语音或其他数据通道组合在一个单一的高带宽信道中。 4. PSK调制解调器的数据传输率:8相的PSK(Phase Shift Keying)调制解调器,其波特率为1600波特,每个相位代表2^3=8位,所以数据传输...

    TIA博途-顺序队列全局FB库文件-GF-sequential-Queue-FIFO.zip

    5. **Syncronization(同步)**:在多线程或多任务环境中,可能需要确保对队列的操作是线程安全的,防止数据竞争。 在使用这个库文件时,用户可以方便地在TIA博途中调用GF_sequential_Queue_FIFO,设置输入参数,...

    2021最新5G高级考试题库及答案-白山市XX通信公司面试试题.pdf

    11. **SS/PBCH block符号数**:一个SS/PBCH block包含4个OFDM symbols。 12. **静态功率控制**:静态功率控制可以应用于PDCCH,以及其他信道或信号如PBCH、SS和SI-RS。 13. **AAU5612前传接口协议**:正确答案应该...

    下行信道映射题目.docx

    在本题目中,主要涉及的是SSB(Syncronization Signal Block,同步信号块)的时频位置映射,包括PSS(Primary Synchronization Signal,主同步信号)、SSS(Secondary Synchronization Signal,辅同步信号)、DMRS...

    5G问题定位.docx

    5G网络的问题定位涉及到多个关键领域,主要包括覆盖评估、RF优化原则以及针对弱覆盖、越区覆盖和重叠覆盖的解决方案。5G网络与LTE在覆盖指标上有显著区别,主要体现在RSRP(Reference Signal Received Power,参考...

    5G模拟考试题.pdf

    它们的周期可以是5/10/20/40/80/160ms,并且在一个系统帧的时间窗内传输。默认情况下,如果未定义周期,则默认为20ms。 5. **Measurement Gap**:这是用于UE进行测量的预留时隙。在网络配置中,可以为每个UE配置...

    2020年最新5G高级考试题库及答案-三明市某动通信有限公司分公司面试试题等两套.pdf

    6. **EN-DC(Enhanced NodeB - Dual Connectivity)测量**:问题6中,MCG(Macro Cell Group)进行NR邻区测量使用SSB(Syncronization Signal Block)参考信号,这有助于在5G和4G之间的双连接中优化性能。...

    R1-1701161_5GCommunications_

    PNT-RS是5G NR系统中的一个重要组成部分,主要用于校准和补偿由相位噪声引起的信道质量恶化,以确保数据传输的准确性和可靠性。 1. **5G NR标准**:5G New Radio (NR) 是3rd Generation Partnership Project (3GPP)...

    电信设备-小区重新选择信令方法.zip

    在移动通信系统中,小区重新选择是至关重要的一个过程,它涉及到用户设备(UE)如何在不同小区之间切换以保持最佳的通信质量。本资料主要关注的是电信设备中执行小区重新选择时所采用的信令方法。小区重新选择不仅是...

    rust-gpu-snippets:Rust片段和用于学习的示例

    "particle.rs"是项目中的一个核心文件,它包含了一个粒子系统实例。粒子系统通常用于创建视觉效果,如烟雾、火焰、水波等,广泛应用于视频游戏和图形设计。在这个示例中,粒子的位置和大小存储在CPU的缓冲区中。CPU...

Global site tag (gtag.js) - Google Analytics