相关疑难解决方法(0)

StaTaskScheduler和STA线程消息泵送

TL; DR:运行任务中的死锁StaTaskScheduler.长版:

我使用的是StaTaskSchedulerParallelExtensionsExtras中通过平行小组,举办由第三方提供的一些遗留STA COM对象.StaTaskScheduler实现细节的描述如下:

好消息是TPL的实现能够在MTA或STA线程上运行,并考虑到底层API的相关差异,如WaitHandle.WaitAll(当方法提供多个等待句柄时,它只支持MTA线程).

我认为这意味着TPL的阻塞部分将使用等待API来提供消息,例如CoWaitForMultipleHandles,以避免在STA线程上调用时出现死锁情况.

在我的情况下,我相信发生以下情况:进程内STA COM对象A调用进程外对象B,然后期望从B通过回调作为传出调用的一部分.

以简化形式:

var result = await Task.Factory.StartNew(() =>
{
    // in-proc object A
    var a = new A(); 
    // out-of-proc object B
    var b = new B(); 
    // A calls B and B calls back A during the Method call
    return a.Method(b);     
}, CancellationToken.None, TaskCreationOptions.None, staTaskScheduler);
Run Code Online (Sandbox Code Playgroud)

问题是,a.Method(b)永远不会回来.据我所知,这是因为内部阻塞等待BlockingCollection<Task>不会引发消息,因此我对引用语句的假设可能是错误的.

EDITED相同的代码工作测试WinForms应用程序的UI线程上执行时(即,提供TaskScheduler.FromCurrentSynchronizationContext()的,而不是staTaskSchedulerTask.Factory.StartNew).

解决这个问题的正确方法是什么?我应该实现一个自定义同步上下文,它将显式地使用消息CoWaitForMultipleHandles …

.net c# com task-parallel-library async-await

27
推荐指数
2
解决办法
9314
查看次数

如何将消息发布到运行消息泵的STA线程?

因此,在此之后,我决定在专用的STA线程上显式实例化COM对象.实验表明COM对象需要一个消息泵,我通过调用它来创建Application.Run():

private MyComObj _myComObj;

// Called from Main():
Thread myStaThread = new Thread(() =>
{
    _myComObj = new MyComObj();
    _myComObj.SomethingHappenedEvent += OnSomthingHappened;
    Application.Run();
});
myStaThread.SetApartmentState(ApartmentState.STA);
myStaThread.Start();
Run Code Online (Sandbox Code Playgroud)

如何从其他线程发布STA线程的消息泵消息?

注意: 为了简洁起见,我对问题进行了大量编辑.@Servy的答案的某些部分现在似乎无关紧要,但它们是针对原始问题的.

c# com interop message-queue sta

14
推荐指数
1
解决办法
8494
查看次数

如何在超时期限后取消任务等待

我正在使用此方法以编程方式实例化Web浏览器,导航到URL并在文档完成时返回结果.

如果文档加载时间超过5秒,我将如何停止TaskGetFinalUrl()返回null

我见过许多使用a的例子,TaskFactory但我无法将其应用于此代码.

 private Uri GetFinalUrl(PortalMerchant portalMerchant)
    {
        SetBrowserFeatureControl();
        Uri finalUri = null;
        if (string.IsNullOrEmpty(portalMerchant.Url))
        {
            return null;
        }
        Uri trackingUrl = new Uri(portalMerchant.Url);
        var task = MessageLoopWorker.Run(DoWorkAsync, trackingUrl);
        task.Wait();
        if (!String.IsNullOrEmpty(task.Result.ToString()))
        {
            return new Uri(task.Result.ToString());
        }
        else
        {
            throw new Exception("Parsing Failed");
        }
    }

// by Noseratio - http://stackoverflow.com/users/1768303/noseratio    

static async Task<object> DoWorkAsync(object[] args)
{
    _threadCount++;
    Console.WriteLine("Thread count:" + _threadCount);
    Uri retVal = null;
    var wb = new WebBrowser();
    wb.ScriptErrorsSuppressed = …
Run Code Online (Sandbox Code Playgroud)

.net c# console-application webbrowser-control task-parallel-library

13
推荐指数
1
解决办法
2万
查看次数

同步等待而不阻止UI线程

是否有一个同步等待函数不会占用.NET WPF中的UI线程?就像是:

Sub OnClick(sender As Object, e As MouseEventArgs) Handles button1.Click
     Wait(2000) 
     'Ui still processes other events here
     MessageBox.Show("Is has been 2 seconds since you clicked the button!")
End Sub
Run Code Online (Sandbox Code Playgroud)

.net vb.net wpf multithreading wait

8
推荐指数
1
解决办法
5898
查看次数

如何在提供WPF Dispatcher事件时等待WaitHandle?

有人给我发了电子邮件,询问我是否有WaitOneAndPumpWPF 的版本.目标是WaitHandle.WaitOne在同一堆栈帧上等待句柄(类似于)并在等待时泵送WPF Dispatcher事件.

我真的不认为这样的API应该用于任何生产代码,无论是WinForms还是WPF(可能除了UI自动化之外).WPF没有暴露WinForms的显式版本DoEvents,这是一个非常好的设计决策,考虑DoEventsAPI一直在滥用的公平份额.

然而,这个问题本身很有意思,所以我将把它作为一个练习并发布任何我想出的答案.如果有兴趣,请随意发布您自己的版本.

.net c# wpf multithreading wait

4
推荐指数
1
解决办法
5058
查看次数

等待Parallel.For

我知道没有必要等待,Parallel.For但是因为在Parallel.For我想等待Parallel.For完成期间正在处理 UI Windows 消息(WinForms 消息泵)。

将 a 封装在 aParallel.ForTask,然后等待它是个好主意吗?有没有更好的办法?

谢谢。

CancellationTokenSource token = new CancellationTokenSource();

const int len = 100;

double[] array = new double[len];

Task t = Task.Factory.StartNew(delegate {
   Parallel.For(0, len, delegate(int i, ParallelLoopState loopState) {

   array[i] += 1;

   });

try
{
   t.Wait(token.Token);
}
catch (OperationCanceledException e)
{
   rc = false;
}
Run Code Online (Sandbox Code Playgroud)

.net c# task-parallel-library

3
推荐指数
1
解决办法
1万
查看次数

如何提取COM消息?

我想等待WebBrowser控件完成导航.所以我创建一个事件,然后我想等待它被设置:

procedure TContoso.NavigateToEmpty(WebBrowser: IWebBrowser2);
begin
   FEvent.ResetEvent;
   WebBrowser.Navigate2('about:blank'); //Event is signalled in the DocumentComplete event

   Self.WaitFor;
end;
Run Code Online (Sandbox Code Playgroud)

然后我在事件中设置DocumentComplete事件:

procedure TContoso.DocumentComplete(ASender: TObject; const pDisp: IDispatch; const URL: OleVariant);
var
    doc: IHTMLDocument2;
begin
    if (pDisp <> FWebBrowser.DefaultInterface) then
    begin
       //This DocumentComplete event is for another frame
       Exit;
    end;

    //Set the event that it's complete
    FEvent.SetEvent;
end;
Run Code Online (Sandbox Code Playgroud)

问题在于如何等待此事件发生.

等待它

第一反应是等待事件被触发:

procedure TContoso.WaitFor;
begin
   FEvent.WaitFor;
end;
Run Code Online (Sandbox Code Playgroud)

问题在于DocumentComplete事件永远不会触发,因为应用程序永远不会空闲,以允许COM事件通过.

忙碌的睡眠等待

我的第一反应是忙着睡觉,等待一面旗帜:

procedure TContoso.NavigateToEmpty(WebBrowser: IWebBrowser2);
begin
   FIsDocumentComplete := …
Run Code Online (Sandbox Code Playgroud)

windows delphi com events winapi

3
推荐指数
1
解决办法
372
查看次数