发个同步锁的代码。欢迎来看看不足的地方。
using System;
using System.Diagnostics;
#region class Lostinet.HashCodeLock
namespace Lostinet
{
using System;
using System.Collections;
using System.Reflection;
using System.Threading;
using System.Diagnostics;
#region class HashCodeLock
[Serializable] public sealed class HashCodeLockTimeoutException:Exception
{
public HashCodeLockTimeoutException(string msg):base(msg){}
}
public sealed class HashCodeLock : MarshalByRefObject
{
#region class Allocator
class Allocator
{
ArrayList al=new ArrayList();
public object Alloc(object obj)
{
object n=obj;
lock(al.SyncRoot)
{
int index=al.IndexOf(n);
if(index!=-1)
{
n=al[index];
}
al.Add(n);
return n;
}
}
public object Release(object obj)
{
object n=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;
}
}
}
#endregion
#region class InternalLock
class InternalLock:IDisposable
{
HashCodeLock h;
object o;
public InternalLock(HashCodeLock hcl,object obj,int timeout)
{
object syncobj=hcl.ac.Alloc(obj);
bool enterok=false;
try
{
enterok=Monitor.TryEnter(syncobj,timeout);
if(!enterok)
throw(new HashCodeLockTimeoutException("lock timeout"));
}
finally
{
if(!enterok)
hcl.ac.Release(obj);
}
h=hcl;
o=obj;
SetStackTrace();
}
string s=" unknown method (not query in release) ";
[Conditional("DEBUG")]
void SetStackTrace()
{
try
{
StackTrace st=new StackTrace(3);//skip at lease 3 frame
for(int i=0;i<st.FrameCount;i++)
{
MethodBase mb=st.GetFrame(i).GetMethod();
if(mb.ReflectedType!=typeof(HashCodeLock))
{
s=mb.ReflectedType.FullName+":"+mb.ToString();
return;
}
}
}
catch
{
}
}
public void Dispose()
{
if(h==null)
throw(new Exception("lock at "+s+" already released!"));
Monitor.Exit(h.ac.Release(o));
h=null;
o=null;
}
~InternalLock()
{
if(h!=null)
{
try
{
//回收对象。但无法使用Monitor.Exit
h.ac.Release(o);
//不同的线程了,Monitor.Exit(h.ac.Release(o));不起作用
}
finally
{
throw(new Exception("lock at "+s+" have not released!"));
}
}
}
}
#endregion
#region instance
Allocator ac=new Allocator();
public IDisposable Lock(object obj)
{
if(obj==null)throw(new ArgumentNullException("obj"));
return new InternalLock(this,obj,Timeout.Infinite);
}
public IDisposable Lock(object obj,int msTimeout)
{
if(obj==null)throw(new ArgumentNullException("obj"));
return new InternalLock(this,obj,msTimeout);
}
public IDisposable Lock(object obj,TimeSpan tsTimeout)
{
if(obj==null)throw(new ArgumentNullException("obj"));
return new InternalLock(this,obj,(int)tsTimeout.TotalMilliseconds);
}
#endregion
#region static
static HashCodeLock hcl=new HashCodeLock();
/// <summary>
/// 用于全局的HashCodeLock
/// </summary>
static public HashCodeLock GlobalLock
{
get
{
return hcl;
}
}
#endregion
}
#endregion
}
#endregion
namespace ConsoleApplication1
{
using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Threading;
using System.Text;
using Lostinet;
class Class1
{
static ManualResetEvent mre=new ManualResetEvent(false);
[MTAThread]
static void Main(string[] args)
{
//启动10条线程
for(int i=0;i<10;i++)
new Thread(new ThreadStart(
new Job(i).Start
))
.Start();
Thread.Sleep(1000);
Console.WriteLine("Start!");
mre.Set();
}
class Job
{
///用于同步任务的私有锁
static HashCodeLock JobLock=new HashCodeLock();
int i;
public Job(int index)
{
i=index;
}
public void Start()
{
mre.WaitOne();
//随机等待一些时间。打乱Job的顺序
Thread.Sleep(new Random(i*DateTime.Now.Millisecond).Next(20));
int ms=3000;//默认等待3秒
if(i==5)
ms=300; //index5任务超时(如果它不是前2位执行的Job)
// if(i==8)
// {
// //错误的用法!..没有使用using..
// JobLock.Lock( int.Parse("11") );
// GC.Collect();
// }
try
{
//换成相等当不同引用的string就无法锁住。。
//lock(11.ToString())
//可以使用全局的HashCodeLock
//using(HashCodeLock.GlobalLock.Lock( int.Parse("11") , ms ))
//JobLock是私有的,假如程序有其他地方使用了HashCodeLock也不会进行锁定的冲突。
using(JobLock.Lock( int.Parse("11") , ms ))
{
Thread.Sleep(100);
Console.WriteLine("job:"+i+" ok");
Thread.Sleep(100);
}
}
catch(Exception x)
{
Console.WriteLine("job:"+i+" - "+x.GetType().FullName+":"+x.Message);
}
}
}
}
}