Блоки MainThread при выполнении задачи, взаимодействующей с COM - PullRequest
1 голос
/ 07 марта 2012

Я хочу выполнить некоторые длительные задачи в приложении C # GUI (на основе Windows Forms).Сначала я попытался выполнить их параллельно с Task.Factory.StartNew().

. Задачи включают взаимодействие с COM.Когда я выполняю задачу (которая должна была выполняться параллельно), поток main / gui показывает занятый курсор и не отвечает.

Объект, через который выполняются вызовы COM, был создан в главном потоке, которыйиспользует однопотоковую квартиру.В этих сообщениях:

Я читал, что это может быть причиной.

Так что мой вопрос: если это причина, что было бы лекарством?

Вот как выглядит код(упрощенно):

    // the Main() method is a STA which could be important?
    [STAThread]
    static void Main()
    {
     //...
    }


    // inside the MainForm class
    private AComWrapperCreatedByCSharp comWrapper;

    private void button1Click(object sender, EventArgs e)
    {
        var myCancellationSource = new CancellationTokenSource();

        if (someCondition)
        {

            // both alternatives did not work

            //Task.Factory.StartNew(
            ThreadPool.QueueUserWorkItem(
                _ =>
                {
                    try
                    {
                        CancellationToken cancellationToken = myCancellationSource.Token;

                        // the main thread will respond while this tasks sleeps!
                        Thread.Sleep(5000);

                        cancellationToken.ThrowIfCancellationRequested();

                        // that's where the task's thread is when I pause execution 
                        // while the gui is not responding
                        var result = comWrapper.CallSeveralLongerLastingCOMOperations();

                        cancellationToken.ThrowIfCancellationRequested();

                        this.BeginInvoke(new UpdateDelegate(() =>
                        {
                            handle(result);
                        }));
                    }
                    catch (OperationCanceledException)
                    {
                        return;
                    }
                    catch (Exception ex)
                    {
                        threadSafeLogging(string.Format(@"An exception occurred: ""{0}""", ex));
                        return;
                    }
                }

                // I tried adding these lines when starting the Task.Factory.... solution
                //,"factory started thread",_updateProjectsDevicesAndLibrariesTaskCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default
                );

        }
    }

Спасибо

Это решение, упомянутое @Hans Passant:

    // inside the MainForm class
    // the COM access object is no longer created in the main thread
    private AComWrapperCreatedByCSharp comWrapper; // = new AComWrapperCreatedByCSharp;

    private void someInitializationMethodInTheMainThread()
    {
      var th = new Thread(() =>
        {
          comWrapper = CreateComWrapper();
        });
      th.SetApartmentState(ApartmentState.MTA);
      th.Start();
      th.Join();
    }

Если я правильно понял, единственная цель этогопотоком является создание объекта в не STA основного потока!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...