怪不得以前做这个:
void XXX(Guid guid)
{
   lock(guid.ToString())
   {
      //....
   }
}
都觉得根本没有把那段代码作为临界段处理。原来lock只认引用。不任任何对象的比较方法的。。于是我自己做了一个支持所有类型的HashCodeLock
只要对象是纯意义上相等的。那么在哪里进行锁定都是作为临界处理。使用方法就是
using(new HashCodeLock( obj ))
{
}

using(new HashCodeLock( obj , msTimeout ))
{
}
有msTimeout的重载版本中。如果超时那么将抛出异常
using System;
using System.Collections;
using System.Reflection;
using System.Threading;
using System.Diagnostics;using LostinetSample;namespace LostinetSample
{
public class HashCodeLockTimeoutException:Exception
{
public HashCodeLockTimeoutException(string msg):base(msg){}
} ///  <res>
///  <code>
///  using(new LostinetSample.HashCodeLock(111))
///  {
/// //now this thread is synchronized for int 111
///  }
///  </code>
///  </res>
public class HashCodeLock:IDisposable
{
class Allocator
{
class Node
{
int typecode;
int hashcode;
public Node(object obj)
{
typecode=obj.GetType().GetHashCode();
hashcode=obj.GetHashCode();
}
override public bool Equals(object obj)
{
if(obj == null)
return false;
if(obj is Node)
{
Node n=(Node)obj;
return n.typecode==typecode&&n.hashcode==hashcode;
}
return false;
}
override public int GetHashCode()
{
return typecode+hashcode;
}
} static ArrayList al=new ArrayList();
static public object Alloc(object obj)
{
Node n=new Node(obj);
lock(al.SyncRoot)
{
int index=al.IndexOf(n);
if(index!=-1)
{
n=(Node)al[index];
}
al.Add(n);
return n;
}
}
static public object Release(object obj)
{
Node n=new Node(obj);
lock(al.SyncRoot)
{
int index=al.IndexOf(n);
if(index==-1)
throw(new Exception("cant release obj:node not found"));
n=(Node)al[index];
return n;
}
}
}
public HashCodeLock(object obj)
{
Init(obj,Timeout.Infinite);
}
public HashCodeLock(object obj,int msTimeout)
{
Init(obj,msTimeout);
}
public HashCodeLock(object obj,TimeSpan tsTimeout)
{
Init(obj,(int)tsTimeout.Milliseconds);
}
void Init(object obj,int ms)
{
if(obj==null)throw(new ArgumentNullException("obj"));
MethodBase mb=new StackTrace(2).GetFrame(0).GetMethod();
m=mb.ReflectedType.FullName+":"+mb.ToString();
if(!Monitor.TryEnter(Allocator.Alloc(obj),ms))
{
Allocator.Release(obj);
throw(new HashCodeLockTimeoutException("lock timeout"));
}
o=obj;
released=false;
} bool released=true;
object o;
string m; void IDisposable.Dispose()
{
if(released)
throw(new Exception("lock at "+m+" already released!"));
released=true;
Monitor.Exit(Allocator.Release(o));
}
~HashCodeLock()
{
if(!released)
throw(new Exception("lock at "+m+" have not released!"));
}
}
}namespace ConsoleApplication1
{
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
t=new Thread(new ThreadStart(WaitForReady));
t.Start(); for(int i=0;i<10;i++)
new Thread(new ThreadStart(
new Job(i).Start
))
.Start(); Console.WriteLine("Start!");
isReady=true;
}
static bool isReady=false;
static void WaitForReady()
{
while(!isReady)
Thread.Sleep(100);
}
static Thread t; class Job
{
int i;
public Job(int index)
{
i=index;
}
public void Start()
{
t.Join();

int ms=3000;
if(i==5)
ms=300; if(i==8)
{
new HashCodeLock( int.Parse("11") );
GC.Collect();
} try
{
//lock(11.ToString())
using(new HashCodeLock( int.Parse("11") , ms ))
{
Thread.Sleep(100);
W("job:"+i+" ok");
Thread.Sleep(100);
}
}
catch(Exception x)
{
W("job:"+i+" - "+x.GetType().FullName+":"+x.Message);
}
}
static public void W(string str)
{
Console.WriteLine(str);
}
}
}
}

解决方案 »

  1.   

    我有一个小的建议:Node 的 HashCode 最好改为:
    return hashcode ^ typecode;
      

  2.   

    呵呵。。没有关系的。重写GetHashCode只是理论上做做而已。ArrayList.Contains方法使用的是obj.Equals,也就是说,Node.GetHashCode根本还没有用得上。
      

  3.   

    不对吧?我觉得似乎无论你怎么说,这里还是有一点点问题。如果你说你写得GetHashCode没有用,而ArrayList.Contains(obj)用的是
    ((object) obj).Equals(obj2)
    那么就是说 Node n=new Node(obj);
    lock(al.SyncRoot)
    {
    int index=al.IndexOf(n);
    if(index!=-1)这里的index就会永远都会是-1,因为每一个Node都是新的,跟你Node里面装的是什么没有什么关系。而我觉得ArrayList.Contains(obj)用的是
    obj.Equals(obj2)
    也就是Node.Equals(obj2)才对,这样的话只要new Node(obj)里面的obj,的typecode和hashcode都一样的话就会一样。如果这种说法对的话,那么我还是觉得用hashcode^typecode要好一点。
      

  4.   

    arraylist里判断对象是否相等是用object.Equals的。而object.Equals(new Node(111),new Node(111))返回true;
      

  5.   

    哎。。竟然把al.RemoveAt(index);忘记了。。:using System;
    using System.Collections;
    using System.Reflection;
    using System.Threading;
    using System.Diagnostics;using LostinetSample;namespace LostinetSample
    {
    public class HashCodeLockTimeoutException:Exception
    {
    public HashCodeLockTimeoutException(string msg):base(msg){}
    } ///  <res>
    ///  <code>
    ///  using(new LostinetSample.HashCodeLock(111))
    ///  {
    /// //now this thread is synchronized for int 111
    ///  }
    ///  </code>
    ///  </res>
    public class HashCodeLock:IDisposable
    {
    class Allocator
    {
    class Node
    {
    int typecode;
    int hashcode;
    public Node(object obj)
    {
    typecode=obj.GetType().GetHashCode();
    hashcode=obj.GetHashCode();
    }
    override public bool Equals(object obj)
    {
    if(obj == null)
    return false;
    if(obj is Node)
    {
    Node n=(Node)obj;
    return n.typecode==typecode&&n.hashcode==hashcode;
    }
    return false;
    }
    override public int GetHashCode()
    {
    return typecode+hashcode;
    }
    } static ArrayList al=new ArrayList();
    static public object Alloc(object obj)
    {
    object n=new Node(obj);
    lock(al.SyncRoot)
    {
    int index=al.IndexOf(n);
    if(index!=-1)
    {
    n=al[index];
    }
    al.Add(n);
    return n;
    }
    }
    static public object Release(object obj)
    {
    object n=new Node(obj);
    lock(al.SyncRoot)
    {
    int index=al.IndexOf(n);
    if(index==-1)
    throw(new Exception("cant release obj:node not found"));
    n=al[index];
    al.RemoveAt(index);
    return n;
    }
    }
    }
    public HashCodeLock(object obj)
    {
    Init(obj,Timeout.Infinite);
    }
    public HashCodeLock(object obj,int msTimeout)
    {
    Init(obj,msTimeout);
    }
    public HashCodeLock(object obj,TimeSpan tsTimeout)
    {
    Init(obj,(int)tsTimeout.Milliseconds);
    }
    void Init(object obj,int ms)
    {
    if(obj==null)throw(new ArgumentNullException("obj"));
    MethodBase mb=new StackTrace(2).GetFrame(0).GetMethod();
    m=mb.ReflectedType.FullName+":"+mb.ToString();
    if(!Monitor.TryEnter(Allocator.Alloc(obj),ms))
    {
    Allocator.Release(obj);
    throw(new HashCodeLockTimeoutException("lock timeout"));
    }
    o=obj;
    released=false;
    } bool released=true;
    object o;
    string m; void IDisposable.Dispose()
    {
    if(released)
    throw(new Exception("lock at "+m+" already released!"));
    released=true;
    Monitor.Exit(Allocator.Release(o));
    }
    ~HashCodeLock()
    {
    if(!released)
    throw(new Exception("lock at "+m+" have not released!"));
    }
    }
    }namespace ConsoleApplication1
    {
    class Class1
    {
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
    t=new Thread(new ThreadStart(WaitForReady));
    t.Start(); for(int i=0;i<10;i++)
    new Thread(new ThreadStart(
    new Job(i).Start
    ))
    .Start(); Console.WriteLine("Start!");
    isReady=true;
    }
    static bool isReady=false;
    static void WaitForReady()
    {
    while(!isReady)
    Thread.Sleep(100);
    }
    static Thread t; class Job
    {
    int i;
    public Job(int index)
    {
    i=index;
    }
    public void Start()
    {
    t.Join();

    int ms=3000;
    if(i==5)
    ms=300; //index5任务超时 if(i==8)
    {
    //错误的用法!..
    new HashCodeLock( int.Parse("11") );
    GC.Collect();
    } try
    {
    //lock(11.ToString())
    using(new HashCodeLock( int.Parse("11") , ms ))
    {
    Thread.Sleep(100);
    W("job:"+i+" ok");
    Thread.Sleep(100);
    }
    }
    catch(Exception x)
    {
    W("job:"+i+" - "+x.GetType().FullName+":"+x.Message);
    }
    }
    static public void W(string str)
    {
    Console.WriteLine(str);
    }
    }
    }
    }