我想在C#gui应用程序中执行一些持久的任务(基于Windows窗体)。
我首先尝试与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中创建一个对象!