我们假设以下代码在我的应用程序中以类似的方式使用:
//------------------------------------- void UseAllResources () { bool bSuccess1 = false; bool bSuccess2 = false; try { bSuccess1 = Monitor::TryEnter (oResource1,msc_iTimeoutMonitor); if (!bSuccess1) return; bSuccess2 = Monitor::TryEnter (oResource2,msc_iTimeoutMonitor); if (!bSuccess2) return; // work on oResource1 and oResource2 } finally { if (bSuccess2) Monitor::Exit (oResource2); if (bSuccess1) Monitor::Exit (oResource1); } } //------------------------------------- void UseResource1 () { bool bSuccess = false; try { bSuccess = Monitor::TryEnter (oResource1,msc_iTimeoutMonitor); if (!bSuccess) return; // work on oResource1 } finally { if (bSuccess) Monitor::Exit (oResource1); } } //------------------------------------- void UseResource2 () { same like UseResource1(),but using oResource2 }
可能会发生这种情况
(超时为500毫秒)
@t = 0ms,线程B正在执行UseResource2(),需要400ms,
@t = 100ms,线程Z调用UseAllResources(),对oResource1进行锁定,并且必须等待oResource2上的锁定,
@t = 200ms,线程A正在调用UseResource1()并且必须等待oResource1上的锁定,这是由线程Z占用的,
@t = 400ms,线程B完成,线程Z锁定oResource2并开始工作,
@t = 700ms,线程A超时,虽然它只需要50ms并且可以在线程Z仍在等待时工作.
我宁愿让线程Z失败,如果有的话,因为超时应该是所有锁的整体值.
我可以同时开始获取多个锁吗?
解决方法
解决方案可能是使用readerwriterlockslim类.以下代码在构造函数中包装了一个函数(您要完成的工作).或者,您可以将函数移动到DoWork方法以更改访问资源的方式.
LockedResource implmentation
class LockedResource { public delegate void RefAction(); readerwriterlockslim resourceLock; public LockedResource() { //Warning: SupportsRecursion is risky,you should remove support for recursive whenever possible resourceLock = new readerwriterlockslim(LockRecursionPolicy.SupportsRecursion); } public bool DoWork(RefAction work,string threadname,int timeout = -1) { try { if (resourceLock.TryEnterWriteLock(timeout)) { if (work != null) { work(); } } else { Console.WriteLine("Lock time out on thread {0}",threadname); } } finally { Console.WriteLine("{0} releasing resource",threadname); if(resourceLock.IsWriteLockHeld) { resourceLock.ExitWriteLock(); } } return false; } }
样本用法
static void Main(string[] args) { object oResouce1 = "-"; object oResouce2 = "-"; LockedResource lock1 = new LockedResource(); LockedResource lock2 = new LockedResource(); //the event wait handles is not required,only used to block thread so that resource values can be printed out at the end of the program var h1 = new EventWaitHandle(false,EventResetMode.ManualReset); var h2 = new EventWaitHandle(false,EventResetMode.ManualReset); var h3 = new EventWaitHandle(false,EventResetMode.ManualReset); WaitHandle[] waitHandles = { h1,h2,h3 }; var t1 = new Thread(() => { lock1.DoWork(() => { oResouce1 = "1"; Console.WriteLine("Resource 1 set to 1"); },"T1"); h1.Set(); }); var t2 = new Thread(() => { lock2.DoWork(() => { oResouce2 = "2"; Console.WriteLine("Resource 2 set to 2"); Thread.Sleep(10000); },"T2"); h2.Set(); }); var t3 = new Thread(() => { lock1.DoWork(() => { lock2.DoWork(() => { oResouce1 = "3"; Console.WriteLine("Resource 1 set to 3"); oResouce2 = "3"; Console.WriteLine("Resource 2 set to 3"); },"T3",1000); h3.Set(); },"T3"); }); t1.Start(); t2.Start(); t3.Start(); WaitHandle.WaitAll(waitHandles); Console.WriteLine("Resource 1 is {0}",oResouce1); Console.WriteLine("Resource 2 is {0}",oResouce2); Console.ReadLine(); }
产量
Resource 1 set to 1 Resource 2 set to 2 T1 releasing resource Lock time out on thread T3 T3 releasing resource T3 releasing resource T2 releasing resource Resource 1 is 1 Resource 2 is 2
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。