我的应用程序出现了一些问题,我发现“锁定”导致了问题。我已将问题简化为更小的代码,可能会更小。但这会做到的。
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
longProcessTimer = new System.Timers.Timer(3000);
longProcessTimer.Elapsed += LongProcessElapsed;
longProcessTimer.Start();
SomeClass.Current.Start();
}
System.Timers.Timer longProcessTimer;
static string LockingString = "TestString";
private void LongProcessElapsed(object sender, EventArgs e)
{
Debug.WriteLine("Long Process Started");
lock (LockingString)//this lock will block the sublock
{
longProcessTimer.Stop();
Thread.Sleep(10000);//just for demo
longProcessTimer.Start();
}
Debug.WriteLine("Long Process Ended");
}
}
public class SomeClass
{
public static readonly SomeClass Current = new SomeClass();
System.Timers.Timer SubTimer;
Stopwatch stopWatch = new Stopwatch();
protected string SubLockingString = "TestString";
public SomeClass()
{
SubTimer = new System.Timers.Timer(500);
SubTimer.Elapsed += SubTimerElapsed;
}
public void Start()
{
stopWatch.Start();
SubTimer.Start();
}
private void SubTimerElapsed(object sender, EventArgs e)
{
SubTimer.Stop();
stopWatch.Restart();
lock (SubLockingString)
{
Debug.WriteLine("Inside sub lock, " + stopWatch.Elapsed);
}
SubTimer.Start();
}
}
现在,如果LockingString被锁定,它将也锁定SubLockingString。但是,如果我更改任何字符串的值,锁将不会相互干扰。
我知道解决方案,但我很好奇为什么会发生?
答案 0 :(得分:1)
您对String interning犯规。
当编译器看到两个具有相同值但在不同位置的字符串文字时,它将它们都转换为单个字符串对象。因此,您的LockingString
和SubLockingString
指向同一个对象-如果运行ReferenceEquals(LockingString, SubLockingString)
,您将返回true
,这表明它们都是对相同基础字符串的引用
您应该只锁定专用的锁定对象。
写:
private [static] readonly object lockObject = new object();
private [static] readonly object subLockObject = new object();
相反。这样可以保证您有一个唯一的对象可以锁定。
答案 1 :(得分:1)
如here所述,您应该避免使用String
实例作为锁的参数。
这样做的原因是,运行时将对具有相同值的字符串使用相同的引用。这就是您的示例中发生的情况。