C# Windows服务中的线程

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

我创建了一个使用可观察列表的应用程序。我已经创建了ObservableList类threadsafe(我认为),它现在在我的应用程序中运行良好

现在我正在尝试将我的应用程序作为服务安装。这也很好,直到有东西被添加到列表中为止。我想那里的线刚断了。我有以下代码:

/// <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。您可以在这里使用simple
Collection
,因为您不会将它绑定到任何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);
        });
}