锁定操作不起作用
本文关键字:不起作用 操作 锁定 | 更新日期: 2023-09-27 18:29:05
我遇到了一些锁定Action
的代码,发现它不起作用。以下是代码的一个(简化而愚蠢的)版本:
class Program
{
static void Main(string[] args)
{
var settings = new Settings(0);
Action<int> threadAction = i =>
{
BusyBody.DoSomething(settings.GetANumber, settings.SetANumber, i);
};
ThreadPool.QueueUserWorkItem(delegate { threadAction(1); });
ThreadPool.QueueUserWorkItem(delegate { threadAction(2); });
Console.ReadLine();
}
class Settings
{
int i;
public Settings(int i)
{
this.i = i;
}
public int GetANumber() => i;
public void SetANumber(int i) => this.i = i;
}
class BusyBody
{
public static void DoSomething(Func<int> getInt, Action<int> setInt, int i)
{
lock (setInt)
{
Console.WriteLine("Getting int: " + getInt());
Console.WriteLine("i " + i);
setInt(i);
Console.WriteLine("set");
}
}
}
}
我希望这将产生以下输出:
Getting int: 0
i 1
set
Getting int: 1
i 2
set
或
Getting int: 0
i 2
set
Getting int: 2
i 1
set
取决于哪个线程首先通过lock
。然而,这并不是我所看到的。相反,我看到:
Getting int: 0
i 2
Getting int: 0
i 1
set
set
看起来两个线程都进入了lock
。为什么会发生这种情况?被锁定的Action
是来自同一对象的同一方法,所以引用不应该是相同的吗?
如有任何帮助,我们将不胜感激。谢谢
这里的问题是锁定了两个不同的对象。
此行:
BusyBody.DoSomething(settings.GetANumber, settings.SetANumber, i);
是这个的缩写:
BusyBody.DoSomething(new Func<int>(settings.GetANumber), new Action<int>(settings.SetANumber), i);
两个new Func<int>(...)
和new Action<int>(...)
表达式将在每次调用中生成新的委托对象,因此不会锁定同一个对象实例。
如果你想共享这些对象,它们必须创建一次:
...
Func<int> getANumber = settings.GetANumber;
Action<int> setANumber = settings.SetANumber;
Action<int> threadAction = i =>
{
BusyBody.DoSomething(getANumber, setANumber, i);
};
...
当您多次将一个方法强制转换为Action
时(当您传递settings.SetANumber
时),并不意味着您得到相同的Action
对象。您会得到多个执行相同操作的Action
对象。
试试这个:
Action<int> set_action = settings.SetANumber;
Action<int> threadAction = i =>
{
BusyBody.DoSomething(settings.GetANumber, set_action, i);
};
这样可以确保只有一个Action
对象。