C# Windows服务中的线程
我创建了一个使用可观察列表的应用程序。我已经创建了ObservableList类threadsafe(我认为),它现在在我的应用程序中运行良好 现在我正在尝试将我的应用程序作为服务安装。这也很好,直到有东西被添加到列表中为止。我想那里的线刚断了。我有以下代码:C# Windows服务中的线程,c#,multithreading,service,thread-safety,C#,Multithreading,Service,Thread Safety,我创建了一个使用可观察列表的应用程序。我已经创建了ObservableList类threadsafe(我认为),它现在在我的应用程序中运行良好 现在我正在尝试将我的应用程序作为服务安装。这也很好,直到有东西被添加到列表中为止。我想那里的线刚断了。我有以下代码: /// <summary> /// Creates a new empty ObservableList of the provided type. /// </summary> public Observabl
/// <summary>
/// Creates a new empty ObservableList of the provided type.
/// </summary>
public ObservableList()
{
//Assign the current Dispatcher (owner of the collection)
_currentDispatcher = Dispatcher.CurrentDispatcher;
}
/// <summary>
/// Executes this action in the right thread
/// </summary>
///<param name="action">The action which should be executed</param>
private void DoDispatchedAction(Action action)
{
if (_currentDispatcher.CheckAccess())
action.Invoke();
else
_currentDispatcher.Invoke(DispatcherPriority.DataBind, action);
}
/// <summary>
/// Handles the event when a collection has changed.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
DoDispatchedAction(() => base.OnCollectionChanged(e));
}
//
///创建所提供类型的新空ObservableList。
///
公众观察者()
{
//分配当前调度程序(集合的所有者)
_currentDispatcher=Dispatcher.currentDispatcher;
}
///
///在正确的线程中执行此操作
///
///应该执行的操作
私有无效DoDispatchedAction(Action Action)
{
if(_currentDispatcher.CheckAccess())
action.Invoke();
其他的
_currentDispatcher.Invoke(DispatcherPriority.DataBind,action);
}
///
///在集合发生更改时处理事件。
///
///
CollectionChanged上的受保护覆盖无效(NotifyCollectionChangedEventArgs e)
{
DoDispatchedAction(()=>base.OnCollectionChanged(e));
}
调试时,我看到调用了集合.Add(object)
。它启动DoDispatchedAction
函数,调试器最后点击的是\u currentDispatcher.Invoke(DispatcherPriority.DataBind,action)代码>。在此之后,应用程序继续运行,但不再执行Collection.Add(object)
之后的代码。最初将项目添加到ObservableList的代码也不会继续。这就是为什么我认为线死了或者类似的原因
在调试器中检查操作时,我发现存在以下消息:
ApartmentState='\u currentDispatcher.Thread.ApartmentState'引发了
类型为“System.Threading.ThreadStateException”的异常
我怎样才能解决这个问题?我想的方向对吗 据我所知,您有一个应该作为Windows服务运行的核心代码,以及一个使用相同核心代码的WPF应用程序
因此,基本上解决方案中应该有3个项目:
- 执行某些硬件相关工作的核心程序集
- 将作为Windows服务安装的可执行文件。此可执行文件引用核心程序集
- 也引用核心程序集的WPF应用程序
Dispatchers有助于将操作打包回UI线程。这主要用于在WPF应用程序的UI线程中执行一些代码。例如,当您将集合绑定到DataGrid
时,必须在UI线程上触发CollectionChanged
事件,因为绑定会导致UI更新。必须从UI线程更新UI
您的核心程序集不必处理分派器,因为没有要更新的UI。您可以在这里使用simpleCollection
,因为您不会将它绑定到任何UI组件。Windows服务可执行文件也是如此
另一方面,对于您的WPF应用程序,您可以使用绑定在UI组件上的ObservableCollection
(例如DataGrid
)。只有在这个程序集中,您才能确保始终从UI线程更新UI组件(这意味着您需要Dispatcher
)
下面是一个代码示例:
堆芯组件:
public IEnumerable<SomeClass> GetHardwareInfo()
{
return new List<SomeClass> { ... };
}
WPF应用程序(假设它是ViewModel):
//某个UI组件绑定到此可访问的集合
公众可观察收集真菌
{
得到
{
返回此.myCol;
}
设置
{
if(this.mycl!=值)
{
this.myCol=值;
本.RaisePropertyChanged(“MyCol”);
}
}
}
公共void UpdateList()
{
var info=new mycoResistance().GetHardwareInfo();
//现在,marshall返回UI线程以更新集合
Application.Current.Dispatcher.Invoke(()=>
{
this.MyCol=新的可观察集合(info);
});
}
由于这是一项依赖于硬件的服务,因此与通常的LOB风格的应用程序略有不同。不同之处在于:应该触发事件的更改来自应用程序的后端,而整个UI框架和服务体系结构旨在用于前端请求后端提供的数据
你可以通过在它们相遇的地方创造某种“中性点”,将两者结合在一起
在硬件处理组件中,我将有一个持续运行或由硬件中断触发运行的后台线程,并使用从硬件收集的任何数据更新其数据结构。然后,我将有一个同步方法,它可以在调用硬件数据时创建硬件数据的一致快照
在WPF客户机中,将有一个调度程序计时器,它以设置的时间间隔调用此方法,并使用数据快照更新ObservableCollections。这是可能的,因为它会发生在UI线程上。实际上,如果可能,您应该尝试从ObservableCollections中添加和删除项,而不是创建新的集合实例,除非集合中的数据从一个调用到下一个调用完全更改
WCF客户机将只是创建数据快照的方法的包装器:它将仅在调用此类快照时发回
WCF服务的WPF客户端将作为本地WPF客户端工作,只是它将直接调用该服务而不是硬件库,而且我可能会为Dispatcher选择更长的时间间隔,以避免过多的网络流量。为了避免多次发送相同的数据,您可以通过返回一个表示“没有任何更改”的特殊代码对此进行进一步优化,或者使用单独的方法询问数据是否已更改
internal static void Main(string[] args)
{
...
var objs = new MyCoreInstance().GetHardwareInfo();
...
}
// Some UI component is binded to this collection that is obersvable
public ObservableCollection<SomeClass> MyCol
{
get
{
return this.myCol;
}
set
{
if (this.myCol != value)
{
this.myCol = value;
this.RaisePropertyChanged("MyCol");
}
}
}
public void UpdateList()
{
var info = new MyCoreInstance().GetHardwareInfo();
// Now, marshall back to the UI thread to update the collection
Application.Current.Dispatcher.Invoke(() =>
{
this.MyCol = new ObservableCollection(info);
});
}