using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication6 { /// <summary> /// 同步锁机制 /// </summary> public class DpLock { private long _flag = 0; /// <summary> /// 尝试获取锁 /// </summary> /// <param name="loop">迭代次数</param> /// <returns></returns> public bool TryEnter(int loop=10) { int _sleep = 5; int _times = 10; int loopElapse = 0; do { loopElapse++; for (int i = 0; i < _times; i++) { if (Interlocked.CompareExchange(ref _flag, 1, 0) == 1) //尝试对比交换 { return true; //成功获取锁 } } if (!Thread.Yield()) //尝试请求系统调度其他线程 { #if DEBUG Console.WriteLine("sleep"+loopElapse); #endif //如果系统没有可调度的线程 //进入休眠 Thread.Sleep(_sleep); } } while (loopElapse <= loop); return false; } /// <summary> /// 获取锁 /// <remarks> /// </remarks> /// </summary> public void Enter() { int _sleep = 5; int _times = 10; #if DEBUG int loopElapse = 0; #endif do { #if DEBUG loopElapse ++; #endif for (int i = 0; i < _times; i++) { if (Interlocked.CompareExchange(ref _flag, 1, 0) == 1) //尝试对比交换 { return; //成功获取锁 } } if (!Thread.Yield()) //尝试请求系统调度其他线程 { #if DEBUG Console.WriteLine("sleep" + loopElapse); #endif //如果系统没有可调度的线程 //进入休眠 Thread.Sleep(_sleep); } } while (true); } /// <summary> /// 释放锁 /// <remarks> /// 这个方法必须要调用,否则其他线程将进入死循环 /// </remarks> /// </summary> public void Exit() { #if DEBUG if (Interlocked.Read(ref _flag) != 1) { //************** 这里报错 _flag值:1 *************** throw new Exception("flag:"+ Interlocked.Read(ref _flag)); } #endif do { } while (Interlocked.CompareExchange(ref _flag,0,1)==0); ; } } }
你外边调用的代码中是不是出现了用TryEnter返回false但同样也尝试Exit了?
代码前半部分没什么问题,但最后这个Exit方法在if条件执行完的时候(前提是上面有包含上面这句话的代码),这个时候读到的是0,但进了throw中的read前有另外一个线程获取到了锁,所以这里你读到的就是1了。
谢谢,问题找到了,犯了低级错误