Tag: 死锁

Task.Run继续在同一个线程上导致死锁

考虑以下我将要同步等待的异步方法。 等一下,我知道。 我知道它被认为是不好的做法并导致死锁 ,但我完全意识到这一点并采取措施通过使用Task.Run包装代码来防止死锁。 private async Task BadAssAsync() { HttpClient client = new HttpClient(); WriteInfo(“BEFORE AWAIT”); var response = await client.GetAsync(“http://google.com”); WriteInfo(“AFTER AWAIT”); string content = await response.Content.ReadAsStringAsync(); WriteInfo(“AFTER SECOND AWAIT”); return content; } 这个代码肯定会死锁(在具有SyncronizationContext的环境中,如在ASP.NET之类的单个线程上调度任务),如果这样调用: BadAssAsync().Result 。 我面临的问题是即使使用这种“安全”包装器,它仍然偶尔会出现死锁。 private T Wait1(Func<Task> taskGen) { return Task.Run(() => { WriteInfo(“RUN”); var task = taskGen(); return task.Result; }).Result; […]

又一个C#死锁调试问题

我使用VS2010 Professional在C#中构建了一个multithreading应用程序。 这是一个相当大的应用程序,我们之前已经经历过分类GUI交叉线程和死锁问题,但在过去的一个月里,我们注意到当它闲置大约20-30分钟时似乎锁定了。 该应用程序是无响应的,虽然当其他窗口被拖到应用程序前面并在其上面时它会重新绘制,但GUI似乎仍然被锁定… …(如果GUI线程被使用了相当长的时间) )关闭,最大化和最小化按钮也是无响应的,当点击时,应用程序的标题中不显示小(无响应…)文本,即Windows仍然认为它运行正常。 如果我使用调试器中断/暂停应用程序,并查看正在运行的线程。 我们的托管代码有3个线程正在运行,还有一些其他工作线程无法显示源代码。 运行的3个线程是: 主/ GUI线程 一个无限循环的线程 一个无限循环的线程 如果我进入线程2和3,它们似乎正在循环。 它们不共享锁(即使使用主GUI线程),它们根本不使用GUI线程。 然而,当进入主/ GUI线程时,它在Application.Run上被破坏了…… 这个问题让我感到僵局,但我不明白的是,如果它是死锁,为什么我看不到主/ GUI线程挂起的代码行? 任何帮助将不胜感激! 如果您需要更多信息,请与我们联系… 干杯, 袋鼠 ————————————————– – -解 – – – – – – – – – – – – – – – – – – – – – – – —- 好的,所以问题现在解决了。 感谢大家的建议! 非常感激! 我已经标记了解决我最初确定应用程序挂起的主/ UI线程的问题的答案(我没有关闭“启用我的代码”选项)。 […]

在WebAPI中使用ContinueWith进行死锁

作为通过Web API公开一些现有代码的一部分,我们遇到了很多死锁。 我已经能够将这个问题提炼到这个非常简单的例子中,这个例子将永远挂起: public class MyController : ApiController { public Task Get() { var context = TaskScheduler.FromCurrentSynchronizationContext(); return Task.FromResult(1) .ContinueWith(_ => { }, context) .ContinueWith(_ => Ok(DateTime.Now.ToLongTimeString()), context); } } 对我来说,这段代码看起来很简单。 这可能看起来有点人为,但这只是因为我尝试尽可能地简化问题。 看起来像这样链接的两个ContinueWith会导致死锁 – 如果我注释掉第一个ContinueWith(实际上并没有做任何事情),它会正常工作。 我也可以通过不给出特定的调度程序来“修复”它(但这对我们来说不是一个可行的解决方案,因为我们的实际代码需要在正确/原始的线程上)。 在这里,我将两个ContinueWiths放在一起,但在我们的实际应用中,有很多逻辑正在发生,而ContinueWiths最终来自不同的方法。 我知道我可以使用async / await重写这个特定的例子,它会简化一些事情,似乎可以修复死锁。 但是,我们在过去几年中已经编写了大量遗留代码 – 其中大部分都是在异步/等待出现之前编写的,所以它大量使用了ContinueWith。 如果我们能够避免它,重写所有逻辑并不是我们现在想做的事情。 像这样的代码在我们遇到的所有其他场景(桌面应用程序,Silverlight应用程序,命令行应用程序等)中运行良好 – 它只是给我们这些问题的Web API。 有没有什么可以一般地解决这种僵局? 我正在寻找一种解决方案,希望不会重新编写所有的ContinueWith来使用async / await。 更新: 上面的代码是我控制器中的整个代码。 我试图用最少量的代码使这个可重复。 […]

C#:从锁定块调用事件

我经常听说在调用事件监听器之前解锁所有锁是个好主意,以避免死锁。 但是,由于lock {}块可以由C#中的同一个线程重入,是否可以从锁定块调用事件,或者我是否需要复制相关状态数据并在锁定块外调用事件? 如果没有,请举例说明从lock {}块中调用事件是否有问题。 谢谢

如何在SqlDataReader.Read()期间从死锁exception中恢复

我的.NET应用程序的事件日志显示它在从Sql Server读取时偶尔会出现死锁。 这通常非常罕见,因为我们已经优化了查询以避免死锁,但它们有时仍会发生。 在过去,我们在SqlCommand实例上调用ExecuteReader函数时发生了一些死锁。 为了解决这个问题,我们添加了重试代码,以便再次运行查询,如下所示: //try to run the query five times if a deadlock happends int DeadLockRetry = 5; while (DeadLockRetry > 0) { try { return dbCommand.ExecuteReader(); } catch (SqlException err) { //throw an exception if the error is not a deadlock or the deadlock still exists after 5 tries if (err.Number != […]

Winforms调用异步方法挂起程序

我一直在解决这个问题,但现在我真的想了解出了什么问题。 我有一个相当简单的应用程序(它是youtrack的turtoise SVN插件,但我可以用一个简单的winforms应用程序重现这个问题)。 我有一个异步方法ResolveIssue public async Task ResolveIssue(Issue issue, int revision, string[] pathList) { await Task.Delay(1000); return true; } 我需要做的就是创建一个死锁,在Button事件处理程序中调用这个异步方法,并调用Task.Wait或Task.Result ,就像这样 private void buttonOk_Click(object sender, System.EventArgs e) { var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList); if (asyncResolvedIssue.Result) {} // <== deadlock! } 现在我明白拥有异步方法并主动等待它是相当奇怪的,但为什么会产生死锁?!

为什么ffmpeg在进程中间随机停止?

ffmpeg感觉好像花了很长时间。 然后我看看我的输出文件,我看到它在6到8mbs之间停止。 完全编码的文件大约是14mb。 为什么ffmpeg会停止? 我的代码锁定了StandardOutput.ReadToEnd();. 我不得不杀死这个过程(看到它不会移动超过10秒,当我看到它每秒更新一次)然后我得到stdout和错误的结果。 stdout是“”stderr在下面。 输出消息显示文件大小已结束。 我也看到停止时CPU使用率下降。 我从视觉工作室复制了这个论点。 CD到同一工作目录并运行cmd(bin / ffmpeg)并粘贴参数。 它能够完成。 注意:我必须先退出并错误检查是否有故障。 int soundProcess(string infn, string outfn) { string aa, aa2; aa = aa2 = “DEAD”; var app = new Process(); app.StartInfo.UseShellExecute = false; app.StartInfo.RedirectStandardOutput = true; app.StartInfo.RedirectStandardError = true; //*/ app.StartInfo.FileName = @”bin\ffmpeg.exe”; app.StartInfo.Arguments = string.Format(@”-i “”{0}”” -ab 192k -y {2} […]

如何安全地混合同步和异步代码?

我有这个纯粹同步的库。 它暴露了同步方法,我有客户端使用它。 对于想要使用它的人,我将底层实现更改为异步和公开的异步方法。 但现在我有很多复制代码。 异步代码似乎表现更好。 我希望现有客户能够利用它,我想消除代码重复。 有没有安全的方法来保持同步签名和调用异步实现? 在打电话时我特别害怕死锁.Result和.Wait。

如何调试死锁?

除此之外我不知道我现在是否可以重现它(我已经使用这个特定的应用程序一两个星期没有问题),假设我在VS调试器中运行我的应用程序,如何它应该在它发生后调试死锁吗? 如果我暂停程序并因此看到不同的线程发生在哪里,我认为我可能能够进入调用堆栈,但是单击暂停只会使Visual Studio陷入死锁,直到我杀死我的应用程序。 除了浏览我的源代码树以寻找潜在问题之外,还有其他方法吗? 一旦出现问题,是否有办法获得调用堆栈以查看问题所在? 任何其他可能有用的工具/提示/技巧?

使用lock(this)来说明死锁的示例代码

我读过几篇文章和post,说lock(this) , lock(typeof(MyType)) , lock(“a string”)都是不好的做法,因为另一个线程可以锁定同一个键并导致死锁。 为了理解这个问题,我试图创建一些示例代码来说明死锁,但一直无法解决这个问题。 有人可以写一个简洁的代码来说明这个经典问题吗? 请保持简短,我只能在较小的块中消化代码。 编辑:我认为lassevk总结得很好; 真正的问题是你失去了对锁的控制。 一旦发生这种情况,您无法控制锁被调用的顺序,并且您允许潜在的死锁情况。 lock(this) , lock(typeof(MyType))等都是你选择了一个无法控制的锁的情况。