我已经编写了自己的timer类,它是Windows多媒体定时器的包装器。
我将计时器类建模在.NET的System.Timers.Timer类上。
我很难理解为什么.NET的计时器在同步对象上调用BeginInvoke,而不是Invoke
if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
{
this.SynchronizingObject.BeginInvoke(intervalElapsed, new object[]{this, elapsedEventArgs};
}
else
{
intervalElapsed(this, elapsedEventArgs);
}我的理解是,BeginInvoke最终应该通过调用EndInvoke来匹配。没有找到EndInvoke。
BeginInvoke在这里会更好呢?BeginInvoke,这是否意味着我的类的计时器事件可以在以前的事件完成之前触发(重新进入问题)?这会不会挫败(某些)与同步对象同步的目的?发布于 2021-04-28 06:40:22
Invoke方法阻塞调用线程,直到完成所提供的委托的执行为止,由于各种原因,这可能需要很长时间。例如,委托可能包含阻塞调用,或者目标上下文可能暂时被阻塞,等等。在System.Timers.Timer类的情况下,调用线程总是一个ThreadPool线程,这是一个有限的资源池。阻塞ThreadPool线程是个坏主意,因为它很容易导致池的饱和,导致效率低下和响应能力降低。这就是为什么调用BeginInvoke更可取的原因,因为它只是调度委托的执行,而调度通常是一个相当快的操作。不需要调用EndInvoke。
System.Timers.Timer.Elapsed事件在设计上是可重入的,如果它调用Invoke而不是BeginInvoke,它仍然是可重入的。这是因为事件是在线程池上触发的。作为比较,System.Windows.Forms.Timer.Tick事件不是重入者,因为它总是在同一个线程UI线程上触发。System.Timers.Timer.Elapsed事件的可重入性是不使用System.Timers.Timer类而使用异步循环的参数。您可以查看这个问题的例子:定期运行具有指定间隔的异步方法。。不使用该类的其他参数是事件处理程序燕子例外,以及该类不是线程安全的。线程安全类一般不会公开事件,因为事件是固有的非线程安全机制。
发布于 2021-04-28 01:28:44
调用将阻塞当前线程和主线程。
而BeginInvoke只阻塞主线程。
你可以试试wpf。
MainWindow.xaml
<Window x:Class="WpfApp5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp5"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<UniformGrid Columns="1">
<TextBlock Text="{Binding TimeString}"/>
<Button Content="Invoke" Click="Invoke_Button_Click"/>
<Button Content="BeginInvoke" Click="BeginInvoke_Button_Click"/>
</UniformGrid>
</Window>MainWindow.xaml.cs
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WpfApp5
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string tmeString;
public string TimeString
{
get { return this.tmeString; }
set
{
this.tmeString = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TimeString)));
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
Task.Run(() =>
{
while (true)
{
TimeString = $"DateTimeNow : {DateTime.Now}";
Thread.Sleep(1000);
}
});
}
private void BeginInvoke_Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke((Action)SomeWork, null);
//break point here
bool buttonClickEventEnd = true;
}
private void Invoke_Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher.Invoke((Action)SomeWork, null);
//break point here
bool buttonClickEventEnd = true;
}
private void SomeWork()
{
Thread.Sleep(3 * 1000);
}
}
}https://stackoverflow.com/questions/67292170
复制相似问题