Я хочу выполнить некоторые длительные задачи в приложении 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 основного потока!