天道酬勤,学无止境

UI 线程正在阻塞调用 COM 对象的后台线程(UI thread is blocking a background thread calling a COM object)

问题

我正在开发一个通过第三方 COM 库与外部设备通信的应用程序。 我试图让与设备的所有通信都通过后台线程,以防止通信问题搞砸我的应用程序,并摆脱在 UI 线程中进行通信引入的其他一些复杂性。

问题是,每当发生导致主 UI 线程阻塞的事情时(即 MessageBox.Show 被调用,甚至只是在屏幕上移动窗口),与后台线程上的设备的通信也会停止。

有没有办法(没有完全独立的进程)将两个线程分开得足够远,以至于它们不会相互干扰? (注意,完全相同的代码和一些数学计算可以稍微减慢速度,但只有在我使用 COM 库时才会出现问题)

回答1

如果以下两个条件为真,则可以解释您观察到的行为。

  • 第 3 方 COM 库被设计为在单线程单元中运行
  • 您正在 UI 线程上从库中创建类的实例

由于 UI 线程在 STA(单线程单元)中运行,并且 COM 类是在该线程上创建的,因此所有从 UI 线程以外的线程发起的对该类的调用都将被编组到 UI 线程本身上。 如果 UI 线程被阻塞,那么所有对 COM 类的调用也将被阻塞。

回答2

我想填写布赖恩的回答。

可能是您忘记为您的工作线程调用TrySetApartmentState(ApartmentState.STA)吗? 如果是这样,我相信您的工作线程默认在 MTA 中运行,并且所有 STA 对象都在单独的 STA 线程(甚至可能是主 UI 线程)上创建。 您应该确保您的工作线程加入 STA 并查看是否有帮助。

除此之外,COM 对象可以注册为 main-STA。 IIRC,这是不常见的。 Main-STA 对象必须存在于主 UI 线程中。 如果这恰好是您的情况,我相信您唯一的选择是求助于工作进程而不是工作线程。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 在后台线程上执行的领域写入仍会阻止主 UI(Realm write performed on background thread still blocks Main UI)
    问题 在我的应用程序中,我需要定期对 Realm 执行大量写入,在 100 到 10,000 个对象之间的任何位置。 显然这是一个很大的写入,所以我试图在后台执行这个写入,以便用户可以执行其他操作,甚至不会注意到写入。 不幸的是,即使我认为我的写入是在后台线程上执行的,主 UI 仍然被阻塞。 这是我调用以执行写入领域的方法的 jist。 在我循环遍历的数组中的单个对象上重复调用此方法。 看起来我做错了什么吗? 任何帮助将不胜感激。 func writeCustomerToRealm(inputCustomer:Customer) { let qualityOfServiceClass = QOS_CLASS_BACKGROUND let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0) dispatch_async(backgroundQueue, { let realm = try! Realm() realm.beginWrite() realm.add(self.swapCustomerForRealmCustomer(inputCustomer)) try! realm.commitWrite() }) } 回答1 您提供的代码是使用 Realm 执行异步后台写入的正确方法。
  • 在 C# 中,在继续处理 UI 更新的同时等待主线程? (.NET 2.0 CF)(In C#, wait on the mainthread while continuing to process UI updates? (.NET 2.0 CF))
    问题 我想以其他方式阻止主线程上的代码执行,同时仍然允许显示 UI 更改。 我试图想出一个我正在尝试做的事情的简化示例版本; 这是我能想到的最好的方法。 显然它没有表现出我想要的行为,否则我不会发布问题。 我只是希望它提供一些代码上下文来支持我对我希望解决的问题的糟糕解释。 在表单上的按钮单击处理程序中,我有这个: private void button2_Click(object sender, EventArgs e) { AutoResetEvent autoResetEvent = new AutoResetEvent(false); new Thread(delegate() { // do something that takes a while. Thread.Sleep(1000); // Update UI w/BeginInvoke this.BeginInvoke(new ThreadStart( delegate() { this.Text = "Working... 1"; this.Refresh(); Thread.Sleep(1000); // gimme a chance to see the new text })); // do something else that takes a while. Thread.Sleep(1000); //
  • Objective-C中的同步和异步调用与多线程之间有什么区别?(What's the difference between synchronous and asynchronous calls in Objective-C, versus multi-threading?)
    问题 在最长的时间里,我认为异步是在后台线程上运行某些东西的代名词,而同步是在主线程上运行(阻止UI更新和交互)的代名词。 我知道不能在主线程上执行昂贵的操作是因为不允许在主线程被占用时发生UI操作,但是为什么同步麻烦呢? 但是,这引起了我的注意,您可以在主线程上进行异步调用,而在后台线程上进行同步调用。 我总是听到人们说不要同步或在主线程上使用昂贵的调用,因为这会阻塞用户的UI。 我应该确保不要做这两个单独的问题吗? 有什么区别? 回答1 当您同步调用某些内容时,这意味着启动该操作的线程将等待任务完成,然后再继续。 异步意味着它不会等待。 话虽这么说,当人们建议您异步执行一些缓慢或昂贵的过程时,他们隐含地建议您不仅应该异步运行它,而且还应该在后台线程上执行该过程。 目标是释放主线程,以便它可以继续响应用户界面(而不是冻结),因此您正在异步地将任务分配给后台线程。 因此,有两个部分。 首先,以GCD为例,获取一个后台队列(获取一个全局后台队列,或者创建自己的后台队列): // one of the global concurrent background queues dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // or you could
  • 核心数据:父上下文阻塞子(Core Data: parent context blocks child)
    问题 我正在一个带有核心数据的应用程序中进行一些后台处理。 后台处理在子 managedObjectContext 上完成。 上下文初始化: appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate // the moc in appDelegate is created with .MainQueueConcurrencyType mainThreadMOC = appDelegate.managedObjectContext! backgroundMOC = NSManagedObjectContext(concurrencyType:NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType) backgroundMOC?.parentContext = mainThreadMOC 后台处理通过以下方法完成: // download all new transaction log entries func syncItems() { ... set up the query object for parse let moc = CoreDataStore.sharedInstance.backgroundMOC //
  • 处理“重”数据时的 WinForms UI 响应能力(WinForms UI responsiveness when dealing with “heavy” data)
    问题 我正在修改 Windows 窗体以允许在后台加载数据,同时 UI 保持响应。 数据检索和绑定都需要花费大量时间。 理想情况下,我会在后台同时执行这两项操作,但是对于我应该在后台执行哪种 UI 更新(如在主线程之外)存在一些歧义。 在后台显示数据检索和数据绑定的可靠示例将非常有帮助。 回答1 检索可以而且应该被推到后台线程——但是有一些模式可以将它全部放在适当的位置。 基本上,您将启动一个后台线程来检索数据,一旦完成,它将需要合并回 UI 线程以进行实际的 UI 更新(跨线程的 UI 更新不好坏不好)。 后台线程的三种基本方式供您探索 最简单/最有限(和古怪的 IMO)是 BackgroundWorker 组件使用委托和它们的 BeginInvoke()/EndInvoke() 方法提供了易用性和灵活性的良好平衡(并使用 ThreadPool 线程) 使用原始 Thread 对象提供最多的控制,但设置速度比 ThreadPool Threads 慢 我个人倾向于委托选项; 一旦你把模式弄下来,它们就很容易使用。 BackgroundWorker 在前面看起来不错,但有一些问题和缺少管道,使其比您预期的更麻烦。 让我简要介绍一下委托方法; 我会尽快更新... 编辑 这是一些代码,它在 VB 中,但如果您是 C# 人,应该很容易转录。 关于您希望后台线程的行为方式,您还有更多选择
  • 使用线程发出数据库请求(Using threads to make database requests)
    问题 我试图了解线程如何在Java中工作。 这是一个简单的数据库请求,返回一个ResultSet。 我正在使用JavaFx。 package application; import java.sql.ResultSet; import java.sql.SQLException; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextField; public class Controller{ @FXML private Button getCourseBtn; @FXML private TextField courseId; @FXML private Label courseCodeLbl; private ModelController mController; private void requestCourseName(){ String courseName = ""; Course c = new Course(); c.setCCode(Integer.valueOf(courseId.getText())); mController = new
  • 异步进度条更新(Async Progress Bar Update)
    问题 我正在尝试使用async await来基于复制操作更新WinForm上的进度条,但是进度条仅在Copy功能完成后才会更新,然后引发异常,因为它没有更新,所以无法更新在同一线程上? 复制功能不需要与UI交互,但是进度功能需要。 不过,UI并未被阻止,因此它看起来异步部分正在按预期工作,它只是与未交互的UI线程进行交互。 long fileProgress = 0; long totalProgress = 0; bool complete = false; CopyFileEx.CopyFileCallbackAction callback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred) { fileProgress = totalBytesTransferred; totalProgress = totalFileSize; return CopyFileEx.CopyFileCallbackAction.Continue; } async Task Progress() { await Task.Run(() => { while (!complete) { if (fileProgress != 0 &&
  • 当主线程被阻塞在可可应用程序UI不更新(UI does not update when main thread is blocked in Cocoa app)
    问题 我在我的主线程使用NSProgressIndicator,因为我通过我的整个方法运行的进展进行更新。 现在,当我最终调用从不同的类文件的对象,并等待该对象返回一个值,我的主线程,我注意到NSProgressIndicator会消失。 我明白,这是因为主线程被阻塞,直到我从其他物体返回值。 所以我的问题是什么是在主线程中更新UI没有阻止它,并根据需要有在后台和返回值运行到主线程其他对象的推荐方式。 我知道如何使用块,但blockoperations不允许返回值。 我需要的东西,可以帮助这个伪代码: -(IBAction) main { //Update progress indicator UI to show progress //perform an call to another object from another class. // wait till i get its return value. //Update progress indicator UI to show progress // Use this return value to do something. //Update progress indicator UI to show progress } 如果是由其他对象的电话,我注意到定NSProgressIndicator我已经完全消失
  • Web Worker 被 Chrome 中的主线程阻止(Web Worker blocked by main thread in Chrome)
    问题 我有一个网络工作者。 我希望用它定期发出网络请求。 我特别想要的一件事是即使主 JS 执行线程被阻塞(例如,被 window.alert 阻塞)也能发出这些请求。 我正在使用 Chrome 38。 但是,当我尝试在工作程序中发出网络请求时,这些请求似乎被 UI 线程阻止了。 这是一个人为的例子来说明这个问题: 基础.js: var worker = new Worker("/worker.js"); setTimeout(function() { console.log("begin blocking"); var startDt = new Date(); var blockPeriod = 5000; var a; // Obviously we'd never actually do this, but this while loop // is a convenient way to create the problem case (a blocked main // thread). while ((new Date() - startDt) < blockPeriod) { a = 0; } console.log("stop blocking"); }, 3000); 工人.js: var requestInterval = 1000; var
  • 带有同步方法的 Anr 消息(Anr Message with synchronized method)
    问题 当我尝试从数据库中获取数据时出现 ANR public synchronized void insertNewObstacle(Obstacle newObstacle) { SQLiteDatabase db = this.getWritableDatabase(); db.execSQL("Insert into "+OBSTACLES_TABLE+" Values ( ' "+ newObstacle.getLongitude() + "' , ' " + newObstacle.getLatitude() + "' , ' " + newObstacle.getDirection() + "' , ' " + newObstacle.getType() + "' , ' " + newObstacle.getAddress() + "' , '" + newObstacle.getSubmissionTime() + "' , '" + newObstacle.getSubmitterName() + "' )" ); db.close(); } 发生 ANR 是因为我从服务器获取数据,然后在保存后将其保存在本地(线程 1)我试图获取保存的数据(线程 2),这就是我使方法同步的原因。 我的问题是: 为什么它不起作用,我收到了那个愚蠢的 ANR 消息?
  • 再次说明异步等待(Explain async await again)
    问题 这是我的事件处理程序代码: protected async void TestrunSaveExecute() { bool saveResult = await SaveTestRunAsync(); } 为了使UI保持响应,我使用了async / await方法。 以我的理解,我现在可以在SaveTestRunAsync()进行一些冗长的操作而不会阻塞UI,因为它是通过使用await关键字进行解耦的。 private async Task<bool> SaveTestRunAsync() { //System.Threading.Thread.Sleep(5000); --> this blocks the UI await Task.Delay(5000); // this doesn't block UI return true; } 您能解释一下为什么对Thread.Sleep的调用仍然会阻止UI,而Task.Delay不会吗? 回答1 该代码仍在UI线程上运行。 它不在后台线程上运行。 因此,您在该异步方法中执行的任何冗长且昂贵的操作仍会在该时间段内阻止UI。 Thread.Sleep使UI线程进入睡眠状态。 您需要了解这种情况下async和await工作方式。 await这里await基本上是这样说的: 让我们在这里将方法分成两部分。
  • C#关于防止GUI在使用backgroundworker/thread时变得迟钝的问题(C# question on preventing GUI from becoming sluggish when using backgroundworker/thread)
    问题 我正在尝试构建一个登录服务器并不断从中收集数据的小型应用程序。 我遇到的问题是,即使使用后台工作程序或线程,我的 GUI 响应速度也很慢。 当我的应用程序尝试登录到服务器时,我看到“(未响应)”出现在我的登录表单中,但它在几秒钟后登录,而 Windows 没有给出“程序已停止响应...终止应用程序”对话框。 当我单击应用程序上的开始按钮时,我注意到 GUI 变得非常缓慢和无响应。 我想知道如何改善程序的响应时间。 这是使用后台工作程序的登录表单的代码和我的从服务器收集数据的线程的代码。 对于代码的最后一部分格式不正确,我深表歉意,但 SO 是不合作的。 private void btnLogin_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(txtAccount.Text) || string.IsNullOrEmpty(txtPassword.Text)) { MessageBox.Show("Must Enter Username and Password"); return; } btnLogin.Enabled = false; account = txtAccount.Text; password = txtPassword.Text; accountType =
  • SynchronizationContext做什么?(What does SynchronizationContext do?)
    问题 在《 Programming C#》一书中,有一些有关SynchronizationContext示例代码: SynchronizationContext originalContext = SynchronizationContext.Current; ThreadPool.QueueUserWorkItem(delegate { string text = File.ReadAllText(@"c:\temp\log.txt"); originalContext.Post(delegate { myTextBox.Text = text; }, null); }); 我是主题初学者,所以请详细回答。 首先,我不知道上下文是什么意思,程序在originalContext保存了什么? 当触发Post方法时,UI线程将做什么? 如果我问一些愚蠢的事情,请指正我,谢谢! 编辑:例如,如果我只写myTextBox.Text = text; ,该怎么办myTextBox.Text = text; 在方法上有什么区别? 回答1 SynchronizationContext做什么? 简而言之,SynchronizationContext表示可能在其中执行代码的位置。 传递给其Send或Post方法的委托将在该位置被调用。 ( Post是Send的非阻塞/异步版本。)
  • GCD中的并发与串行队列(Concurrent vs serial queues in GCD)
    问题 我正在努力完全理解GCD中的并发和串行队列。 我遇到了一些问题,希望有人能及时明确地回答我。 我正在阅读串行队列的创建和使用,以便一个接一个地执行任务。 但是,如果发生以下情况,会发生什么情况: 我创建一个串行队列我使用dispatch_async (在刚创建的串行队列上)三次来调度三个块A,B,C 将执行以下三个块: 顺序为A,B,C,因为队列是串行的或者同时(在并行线程上),因为我使用了ASYNC调度我读到我可以在并发队列上使用dispatch_sync ,以便一个接一个地执行块。 在那种情况下,为什么甚至不存在串行队列,因为我总是可以使用并发队列,在该队列中我可以根据需要同步分发尽可能多的块? 感谢您的任何很好的解释! 回答1 一个简单的例子:您有一个需要一分钟执行的块。 您将其从主线程添加到队列中。 让我们看一下这四种情况。 异步-并发:代码在后台线程上运行。 控件立即返回主线程(和UI)。 该块不能假定它是在该队列上运行的唯一块异步-串行:代码在后台线程上运行。 控制权立即返回主线程。 该块可以假定它是在该队列上运行的唯一块 sync-并发:代码在后台线程上运行,但主线程等待其完成,从而阻止对UI的任何更新。 该块不能假定它是在该队列上运行的唯一块(我本可以在几秒钟前使用异步添加另一个块) sync-串行:代码在后台线程上运行,但是主线程等待它完成
  • .NET 线程、锁和等待(.NET Threading & Locks & Waiting)
    问题 我试图让我的 GUI 线程在长时间运行的操作中保持响应性。 这些操作必须是同步的,因为它们通常是需要在请求的操作完成之前完成的操作。 我试图用后台工作者、监视器和锁对象来做到这一点。 本质上,我想在长时间运行的进程启动之前启动一个计时器,在后台线程中启动长时间运行的进程并等待后台工作线程以表示它已经完成,然后再继续依赖代码。 如果长时间运行的过程花费的时间太长,则向用户显示“正在加载...”对话框,以便他们知道应用程序没有崩溃。 这方面的一个例子可能是用户单击图形包中的按钮,必须在我们绘制图像之前从磁盘加载大图像,然后打印计算到顶部一百万个小数位的 pi。 我无法从磁盘异步加载图像,这将使 UI 保持响应,因为用户可能会启动另一个扰乱程序状态的操作(即撤消操作)。 我可以简单地将光标更改为沙漏并完成它,但在许多情况下,我希望用户也能够取消操作 - 带有取消按钮的“正在加载...”对话框会照顾到这个还不错。 我最初的目标是使用锁定对象和System.Threading.Monitor.Enter()以便 UI 线程等待长时间运行的线程完成,然后继续执行。 如果计时器在长时间运行的线程完成之前触发,则 UI 线程仍可用于处理事件并在屏幕上绘制对话框。 我遇到的问题是,在 UI 线程尝试获取锁定之前,我无法让后台工作人员锁定对象。 相当烦人的是,我正在使用一些非常黑盒的第 3
  • 处理程序与AsyncTask与线程[关闭](Handler vs AsyncTask vs Thread [closed])
    问题 关门了。 这个问题是基于意见的。 它当前不接受答案。 想要改善这个问题吗? 更新问题,以便可以通过编辑此帖子以事实和引用的形式回答。 1年前关闭。 改善这个问题 我对Android中的Handlers , AsyncTask和Threads之间的区别感到有些困惑。 我已经在StackOverflow上阅读了很多博客和问题。 Handler是后台线程,可为您提供与UI进行通信的功能。 例如,更新进度条应通过Handler完成。 使用处理程序,您可以利用MessagingQueues的优势,因此,如果您要计划消息或更新多个UI元素或执行重复任务。 AsyncTask类似,实际上,它们使用Handler ,但未在UI线程中运行,因此对于获取数据(例如,获取Web服务)非常有用。 稍后,您可以与UI进行交互。 但是, Thread无法与UI交互,提供更多的“基本”线程,您会错过AsyncTask所有抽象。 但是,我想在服务中运行套接字连接。 应该在处理程序或线程中运行,还是在AsyncTask ? 完全不需要UI交互。 我使用的性能是否有所不同? 同时,文档已得到重大改进。 回答1 正如使用Handlers进行Android后台处理的教程中一样,Vogella网站上的AsyncTask和Loaders指出: Handler类可用于注册到线程,并提供一个简单的通道将数据发送到该线程。
  • 为什么显式管理线程是一件坏事?(Why is the explicit management of threads a bad thing?)
    问题 在上一个问题中,我有点失礼了。 你看,我一直在阅读有关线程的文章,并认为它们是自奇异果冻以来最美味的东西。 想象一下我的困惑,当我读到这样的东西时: [T]hreads 是一件非常糟糕的事情。 或者,至少,线程的显式管理是一件坏事 和 跨线程更新 UI 通常表明您正在滥用线程。 由于每次有什么事情让我感到困惑时我都会杀死一只小狗,因此请考虑这是您恢复业力的机会...... 我应该如何使用线程? 回答1 学习线程的热情很棒; 不要误会我的意思。 相比之下,热衷于使用大量线程是我所谓的线程幸福病的症状。 刚刚了解线程功能的开发人员开始提出诸如“我可以在一个程序中创建多少个线程?”之类的问题。 这更像是一个英语专业的学生问“我可以在一个句子中使用多少个单词?” 对作家的典型建议是让你的句子简短而切题,而不是试图将尽可能多的单词和想法塞进一个句子中。 线程也是一样的; 正确的问题不是“我可以创造多少?” 而是“我怎样才能编写这个程序,使线程数成为完成工作所需的最少数量?” 线程解决了很多问题,这是真的,但它们也带来了巨大的问题: 多线程程序的性能分析通常极其困难且非常违反直觉。 我在大量多线程程序中看到过真实世界的例子,其中在不减慢任何其他功能或使用更多内存的情况下使函数更快,从而使系统的总吞吐量更小。 为什么? 因为线程往往就像市中心的街道。 想象一下,在不重新为红绿灯计时的情况下
  • WPF 多线程(WPF Multithreading)
    问题 我正在构建一个 WPF 应用程序,它调用 Web 服务并显示由我的应用程序分解和分析后从服务返回的数据。 我面临的问题是多线程。 每 60 秒使用 DispatcherTimer 进行一次 API 调用。 问题是当这个事件触发时,它会阻塞 UI 线程。 我已经尝试(以我能想到的所有方式)使用 BackgroundWorker 和 Dispatcher 对象(也是委托)从后台线程更新 UI,但我无法弄清楚这一点。 我需要一个示例,显示由后台线程更新的 UI 线程上的标签。 对此的任何帮助都会很棒,因为我快要吓坏了:)。 我看过其他文章,但对我来说意义不大。 请耐心等待,因为我对此很陌生。 这是我想做的一个例子。 我在名为 lblCase 的窗口上有一个标签。 我每 60 秒调用一次 pullData(),我想在不阻塞 UI 的情况下用返回的数据更新 lblCase。 private void pullData() { //API call goes here... lblCase.Content = iCase; } public MainWindow() { InitializeComponent(); DispatcherTimer timer = new DispatcherTimer(); timer.Tick += new EventHandler(timer
  • Handler,Runnable和Thread有什么区别?(What is the different between Handler, Runnable, and Threads?)
    问题 Handler,Runnable和Thread有什么区别? 当我使用android时,我需要在后台运行某些内容。 我使用线程来运行它。 通常,我会编写一个扩展Thread并实现run方法的类。 我还看到了一些示例,这些示例实现了可运行的并传递给可运行的线程。 但是我还是很困惑。 有人可以给我一个清晰的解释吗? 如果可以在Thread的run方法中编写后台代码,那么Runnable有什么意义? 如何在线程内使用Handler以及为什么需要使用它。 Android还有另一种叫做runOnUiThread的东西,我们该如何使用呢? 我知道它用于更新UI。 回答1 为什么要在线程上使用Runnable? Runnable中隔离代码,需要异步运行,从代码是如何运行的。 这使您的代码保持灵活。 例如,可运行对象中的异步代码可以在线程池或专用线程上运行。 Thread已声明您的可运行状态可能不需要访问。 可访问的状态超出了必要,这是糟糕的设计。 线程占用大量内存。 为每个小动作创建一个新线程需要花费处理时间来分配和取消分配此内存。 runOnUiThread实际在做什么? Android的runOnUiThread将Runnable排队以在UI线程上执行。 这很重要,因为您永远不要从多个线程更新UI。 runOnUiThread使用一个Handler 。 请注意,如果UI线程的队列已满
  • C#:阻止函数调用,直到满足条件(C# : Blocking a function call until condition met)
    问题 我正在开发一个C#Winforms应用程序,该应用程序的一部分将使用AsyncUpload(由于需要使用随机回调)而将文件上传到Web服务器,在C#程序中 我有一个简单的for循环,调用了Uploading函数 for(int i=0;i < 10 ; i++) { Uploadfun(); } 这种乐趣带来了一些魔力: Uploadfun() { // Logic comes here // webClient.UploadFileAsync runs a 2nd thread to perform upload .. webClient.UploadFileAsync(uri, "PUT", fileNameOnHD); } 异步上传完成后会调用一个回调 Upload_Completed_callback() { //Callback event } 编辑 逻辑顺序: 有趣被调用(来自循环) 有趣的逻辑已执行并完成。 返回for循环当UploadFileAsync(在另一个线程中运行某些逻辑)结束时,回调将最终被调用 问题在第三点,当执行返回到for循环时,我需要阻止循环继续进行,直到调用回调为止。 回答1 因此,如果我理解正确,则您想调用UploadFileAsync然后阻塞直到异步调用到达您的回调为止。 如果是这样,我会使用AutoResetEvent即