首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用COM对象的BackgroundWorker会导致UI线程挂起

使用COM对象的BackgroundWorker会导致UI线程挂起
EN

Stack Overflow用户
提问于 2020-06-30 02:43:46
回答 1查看 63关注 0票数 0

我有一个专用的类,其中包括一个BackgroundWorker,它负责从队列中运行特定于类的操作-需要使用COM对象的操作。

当应用程序启动时,在运行时从UI线程创建专用类的对象(WPF)。当类的构造函数被调用时,它实例化一个BackgroundWorker,该a运行从UI线程分配的异步出队操作。

但是,当这些操作需要从COM对象产生的数据时,我注意到UI线程在响应用户输入之前等待BackgroundWorker完成操作。

如何隔离以使UI线程不受COM函数的影响,这些函数最多需要10秒才能完成?

代码:

代码语言:javascript
复制
public class User(){
  private BackgroundWorker Worker;
  private Queue<Action> ActionQueue;
  private COM COMObject; // COM is an interface exposed by the COM referenced in VS project
  private bool Registered;

  public User(){
    this.Registered = true;
    this.ActionQueue = new Queue<Action>();
    this.Worker = new BackgroundWorker();
    this.Worker.DoWork += new DoWorkEventHandler(DoWork);
    this.Worker.DoWork += new RunWorkerCompletedEventHandler(WorkerCompleted);
    this.Worker.Worker.WorkerSupportsCancellation = true;
    this.Worker.Worker.RunWorkerAsync();
    this.COMObject = new COM();
  }

  private DoWork(object sender, DoWorkEventArgs e){
    // If there is something to be done (an action) in the queue
    if (ActionQueue.Count > 0){
      // Dequeue the action from the queue
      Action queuedAction = ActionQueue.Dequeue();

      // Do the action
      queuedAction();
    }
  }

  private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
    // While this machine continues to be registered to the app...
    if (this.Registered)
    {
        Worker.RunWorkerAsync();
    }
  }

  public void ConnectToDatabase(){
    Action action = delegate {

      COMObject.Connect(); // function can take up to 10 seconds to return 
      
    }; // end of action delegate

    ActionQueue.Enqueue(action);
  }
}

使用代码(在UI线程中):

代码语言:javascript
复制
User user = new User();
user.ConnectToDatabase();

在我的UI中,在应用程序启动期间,最多可以创建并调用10个User对象进行连接。如果我注释掉User::ConnectToDatabase中的COMObject.Connect();行并将其替换为Thread.Sleep(10000),则UI线程不会等待10+秒。但是,就像现在的代码一样,我注意到在再次处理WPF应用程序中的任何用户输入之前,COMObject.Connect();行确实会导致10+秒。

如何隔离以便与COM对象相关的函数不会影响UI线程的性能?

(注意:与BackgroundWorker一起排队的操作与UI线程没有交互。在这些操作中只更改类特定的属性)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-07 04:10:41

答案总是隐藏在评论中:)

正如@Blindy@jdweng指出的,new COM()是在主UI线程上调用的,而COM对象的所有功能都是在不同的线程上使用的。

此外,我确实使用STAThread属性(this.Worker.SetApartmentState(ApartmentState.STA);)设置了COM对象的线程。

而且,我确实从使用BackgroundWorker改为使用实际的线程。

最后,但并非最不重要的一点是,当@Blindy指出使用Queue<Action>在工作线程(从主UI线程排队)上执行工作时存在的问题时,根据@Anders H的建议,我最终确实使用了ConcurrentQueue<Action>。我会使用Tasks,从我在该主题上所做的大量研究来看,Tasks本可以解决跨线程访问的潜在问题,但是,由于排队的“工作”必须按顺序进行并且与COM对象相关,因此ConcurrentQueue暂时看起来是一个不错的解决方案。但是,稍后将不得不重新考虑这一点。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62644741

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档