C# 锁定和调度程序
我试图重构一些WPF代码,发现了一个奇怪的代码序列。你能帮我理解它的含义吗 我在一个定制的虚拟面板上。Inside MeasureOverride使用Dispatcher延迟调用,虚拟化不再显示的所有项目。请查看为什么可以这样做 对我来说,使用Dispatcher延迟UI线程上的某些调用似乎是一个奇怪的选择。这是我不理解的第一件事,但考虑到代码的其余部分,开发人员可能会选择它,因为他熟悉这个构造。我想将此更改为一个简单的Dispatcher.BeginInvoke-call 无论如何,第二件奇怪的事情是应用的锁定。我假设这样做是为了保护对实例字段的访问,这些字段在MeasureOverride内部的代码和CleanUpItems锁之间共享。但这对我来说毫无意义,因为所有的事情都是在UI线程上执行的,对吗 如果这是真的,那么这段代码实际上可能会引入死锁,以防调度器停止锁内的一个执行,并继续执行需要锁的调度器队列上的另一个任务,对吗?或者WPF是否保证调度程序队列上的任务不会因队列中稍后的其他任务而中断 如果锁的原因是其他原因,那么所有这些想法可能都无关紧要。所以,如果你知道另一个有意义的原因,请与我分享。最后,我想摆脱这把锁,而不产生任何负面后果 PS:ScrollCanvas是在XAML中创建的C# 锁定和调度程序,c#,wpf,multithreading,dispatchertimer,C#,Wpf,Multithreading,Dispatchertimer,我试图重构一些WPF代码,发现了一个奇怪的代码序列。你能帮我理解它的含义吗 我在一个定制的虚拟面板上。Inside MeasureOverride使用Dispatcher延迟调用,虚拟化不再显示的所有项目。请查看为什么可以这样做 对我来说,使用Dispatcher延迟UI线程上的某些调用似乎是一个奇怪的选择。这是我不理解的第一件事,但考虑到代码的其余部分,开发人员可能会选择它,因为他熟悉这个构造。我想将此更改为一个简单的Dispatcher.BeginInvoke-call 无论如何,第二件奇怪
public class ScrollCanvas : VirtualizingPanel, IScrollInfo
{
private readonly DispatcherTimer _idleTimer;
public ScrollCanvas()
{
_idleTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(5), DispatcherPriority.Normal, CleanUpItems, Dispatcher.CurrentDispatcher);
_idleTimer.Stop();
}
protected override Size MeasureOverride(Size availableSize)
{
lock (_idleTimer)
{
//Finding the items to realize
//Generating the children from the item
//realizing the children
//Measuring the children
//Some further updates to other instance fields defined in ScrollCanvas
//I left this out cause this sequence is more that 100 lines of code
if (!_idleTimer.IsEnabled)
{
_idleTimer.Start();
}
}
private void CleanUpItems(int minDesiredGenerated, int maxDesiredGenerated)
{
//This method uses same properties and resources as code in other lock that I left out for clarity
var children = InternalChildren;
var generator = ItemContainerGenerator;
for (var i = children.Count - 1; i >= 0; i--)
{
var childGeneratorPos = new GeneratorPosition(i, 0);
var itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos);
if (itemIndex < minDesiredGenerated || itemIndex > maxDesiredGenerated)
{
generator.Remove(childGeneratorPos, 1);
RemoveInternalChildRange(i, 1);
}
}
}
private void CleanUpItems(object sender, EventArgs eventArgs)
{
_idleTimer.Stop();
lock (_idleTimer)
{
CleanUpItems(_protectedInterval.First, _protectedInterval.Last);
}
}
}
<Style TargetType="local:PageViewer">
<Setter Property="Background"
Value="Transparent"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing"
Value="True" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<local:ScrollCanvas Background="{Binding Background, RelativeSource={RelativeSource AncestorType=local:PageViewer}}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
锁定永远不会导致死锁,因为方法永远不会为了在同一线程上运行其他方法而中断。线程本身可能会被操作系统抢占,以便为另一个线程提供运行时间,但这对单个线程是透明的。由于所有方法都在UI线程上运行是正确的,因此死锁是不可能的,事实上,正如您所怀疑的,锁定只是无用的开销。您继承了一些奇怪的代码:PI同意,对于5毫秒的延迟,计时器并不比简单地调用Dispatcher.BeginInvoke或InvokeAsync好多少。但是根据您在代码中的注释,您没有共享所有受lock\u idleTimer保护的代码,因此我们无法验证代码是否未在其他线程上调用。如果您确定所有代码都在UI线程中执行,则死锁是不可能的,并且lock语句提供的同步是不必要的。