5555...就要hashtable 多线程安全嘛..

先寒一下自己的标题...有感于< 555 不嘛 !我就要 返回值重载 ! >

第一次在Cnblog发文章,很不幸,在文章要完成居然出现了...Internet Exlpore执行了非法操作。.我靠.

起因:
我在实现Xxmm3(一个O/R)的Cache部份时需要一个可多线读写的hashtable。找了一下资料,木找到,如果各位有资料的话,给我提个醒,谢谢。
看了msdn的 Hashtable.Synchronized;
通过集合枚举在本质上不是一个线程安全的过程。甚至在对集合进行同步处理时,其他线程仍可以修改该集合,这会导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。

也就是说,我仍然无法实现多线程安全的读写(在枚举过程,仍然无法改写hashtable)

解决:
为了高效的实现目标,多线程安全的读写hashtable,需要解决三个问题
1。在开始一个或多个枚举时,禁止对hashtable的改写
2。在改写ht,但改写未结束时,不能再开始一个新的枚举。
3。允许多个枚举并发

为了解决1,在开始枚举时,需要设置一个标志m_CanWrite 禁止改写操作。
为了解决2,在改写ht的时,不能设置一个flag m_IsWrite从儿禁止/允许一个新枚举的开始
为了解决3,需要一个枚举计数器,知道最后一个枚举结束时,才能允许改写ht.

一个SafeHashtable类:
using  System;
using  System.Collections;
using  System.Threading;

namespace  ConsoleApplication1
{
    
///   <summary>
    
///  SafeHashtable 的摘要说明。
    
///   </summary>
     public   class  SafeHashtable
    {
        
private  Hashtable ht  =   new  Hashtable();
        
        
private   volatile   bool  m_CanWrite  =   true ;
        
private   volatile   bool  m_IsWrite  =   false ;
        
private   volatile   int  m_EnumerateCount  =   0 ;

        
public  SafeHashtable()
        {

        }

        
private   void  SafeWait()
        {
            
// 如果hastable不允许写
            
// 也就是一个枚举正在进行或另一个写如操作正在发生时
            
// 线程等待知道 m_CanWrite为true
             while ( ! m_CanWrite)
            {
                Thread.Sleep(
10 );
            }
        }

        
public   void  Add( object  key, object  v)
        {
            
// 当Add操作发生时但未结束时
            
// 要保证Remove操作不会不会将m_IsWrite写成true
            
// Remove操作也是一样的道理
             this .SafeWait();
            
this .m_CanWrite  =   false ;
            
this .m_IsWrite  =   true ;
            ht.Add(key,v);
            
this .m_IsWrite  =   false ;
            
this .m_CanWrite  =   true ;
        }

        
public   void  Remove( object  key)
        {
            
this .SafeWait();
            
this .m_CanWrite  =   false ;
            
this .m_IsWrite  =   true ;
            ht.Remove(key);
            
this .m_IsWrite  =   false ;
            
this .m_CanWrite  =   true ;
        }
        
        
public  Hashtable StartEnumerate()
        {
            
// 等带写操作结束
             while (m_IsWrite)
            {
                Thread.Sleep(
10 );
            }
            
this .m_CanWrite  =   false ;
            
this .m_EnumerateCount  ++ ;
            Hashtable eht 
=  Hashtable.Synchronized(ht);
            
            
return  eht;
        }

        
public   void  EndEnumerate()
        {
            
this .m_EnumerateCount  -- ;
            
// 禁止再开始一个枚举
             this .m_IsWrite  =   true ;
            
// 如果这是最后一个枚举
            
// 则允许hashtable可写入
             if  ( this .m_EnumerateCount  <=   0 )
            {
                
this .m_CanWrite  =   true ;
            }
            
// 允许再开始一个枚举
             this .m_IsWrite  =   false ;
        }
    
    }
}


当然你完全可以从让Safehashtable从hashtable继承而来,因为cache操作频繁,我不想使用override
为什么要使用:while(..){sleep()}
我测试了一下,如果不使用Sleep(...),而让while循环体为空的话,十分占用cpu,测试的时候达到了100%.还是Sleep要省一些资源。
需要开始一个枚举的时候,你需要调用 StartEnumerate()枚举结束时,要记得掉用:EndEnumerate这是一个成对操作.否则其他线程就无法再改写ht了。

下面是测试代码:

using  System;
using  System.Collections;
using  System.Threading;

namespace  ConsoleApplication1
{
    
///   <summary>
    
///  Class1 的摘要说明。
    
///   </summary>
     class  Class1
    {
        
// static Hashtable ht = new Hashtable();
         static  SafeHashtable ht  =   new  SafeHashtable();
        
///   <summary>
        
///  应用程序的主入口点。
        
///   </summary>
        
        [STAThread]
        
static   void  Main( string [] args)
        {
            
for  ( int  j  =   1 ;j  <=   3 ;j ++ )
            {
                
for  ( int  i  =   0 ;i  <   10000 ;i  ++ )
                {
                    ht.Add(j
* 1000000   +  i,i * 100 );
                }

                ThreadStart myThreadDelegate 
=   new  ThreadStart(Class1.FreeSpac);
                Thread myThread 
=   new  Thread(myThreadDelegate);
                myThread.Name 
=   " 000 " ;
                myThread.Start();
                myThread 
=   new  Thread(myThreadDelegate);
                myThread.Name 
=   " 999 " ;
                myThread.Start();
                Write(j);
            }
            Console.ReadLine();

        }

        
static   void  FreeSpac()
        {
            Hashtable safeHt 
=  ht.StartEnumerate();
            
// lock(typeof(Class1))
            {
                
// ht.CanWrite = false;
                 foreach (DictionaryEntry entry  in  safeHt)
                {
                    Console.WriteLine(
" Thread[{2}] Key[{0}] Value[{1}] " ,entry.Key,entry.Value,Thread.CurrentThread.Name);
                }
                ht.EndEnumerate();
            }
            
        }

        
static   void  Write( int  j)
        {
            Thread.Sleep(
100 );
            
for  ( int  i  =   10000 ;i  <   20000 ;i ++ )
            {
                ht.Add((i 
+  j * 10000000 ).ToString()  +   " * " ,DateTime.Now);
            }
        }
    }
}

如果文中有什么不当,欢迎拍拍.
 



 

转载于:https://www.cnblogs.com/ocoogo/archive/2005/11/05/269493.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值