我似乎没有找到如何获得SynchronizationContext给定的Thread:
Thread uiThread = UIConfiguration.UIThread;
SynchronizationContext context = uiThread.Huh?;
Run Code Online (Sandbox Code Playgroud)
我为什么需要那个?
因为我需要从前端应用程序的不同位置发布到UIThread.所以我在一个名为的类中定义了一个静态属性UIConfiguration.我在Program.Main方法中设置了这个属性:
UIConfiguration.UIThread = Thread.CurrentThread;
Run Code Online (Sandbox Code Playgroud)
在那一刻我可以肯定我有正确的线程,但是我不能设置像这样的静态属性
UIConfiguration.SynchronizationContext = SynchronizationContext.Current
Run Code Online (Sandbox Code Playgroud)
因为尚未安装该类的WinForms实现.由于每个线程都有自己的SynchronizationContext,因此必须可以从给定Thread对象中检索它,或者我完全错了?
我正在努力学习SynchronizationContext和朋友们.如果我在例如控制台应用程序的开头设置自定义同步上下文.在什么条件下,当前的同步上下文会与我的异步操作一起流动?Task和其他人之间是否存在差异,例如Delegate.BeginInvoke?
void Main()
{
SynchronizationContext.SetSynchronizationContext(new FooContext());
Action a = () =>
{
var current = SynchronizationContext.Current;
//current is null here
};
a.BeginInvoke(null,null);
...sleep
Run Code Online (Sandbox Code Playgroud)
如果我在线程池上执行东西,我是否被迫为当前正在执行我的工作的特定线程分配同步上下文?
c# asynchronous synchronizationcontext task-parallel-library
我在使用HttpClient发送http请求时遇到间歇性死锁,有时它们永远不会返回到await SendAsync我的代码中.我能够找出处理内部请求的线程HttpClient/ HttpClientHandler由于某种原因SynchronizationContext它在死锁期间有一个.我想弄清楚如何使用线程最终得到a SynchronizationContext,通常他们没有.我会假设无论什么对象导致SynchronizationContext设置它也会阻塞Thread,这会导致死锁.
我是否能够在TPL ETW事件中看到任何相关内容?
我该如何解决这个问题?
编辑2:
我注意到这些死锁的地方是在ServiceContractwindows服务中的wcf (参见下面的代码)中.该SynchronizationContext所导致的问题实际上是一个是WindowsFormsSynchronizationContext,我以为是一些控制入门创建并造成没有清理正确(或者类似).我意识到几乎可以肯定不应该在Windows服务中发生任何Windows窗体的事情,我并不是说我同意它是如何使用的.但是,我没有使用它编写任何代码,我不能轻易地改变所有的引用.
编辑:这是我遇到问题的wcf服务的一般概念的一个例子.这是一个简化版本,而不是确切的代码:
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
internal class SampleWcfService
{
private readonly HttpMessageInvoker _invoker;
public SampleWcfService(HttpMessageInvoker invoker)
{
_invoker = invoker;
}
[WebGet(UriTemplate = "*")]
[OperationContract(AsyncPattern = true)]
public async Task<Message> GetAsync()
{
var context = WebOperationContext.Current;
using (var request = CreateNewRequestFromContext(context))
{
var response = await …Run Code Online (Sandbox Code Playgroud) .net c# synchronizationcontext task-parallel-library async-await
我正在尝试更多地了解它SynchronizationContext,所以我制作了这个简单的控制台应用程序:
private static void Main()
{
var sc = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(sc);
DoSomething().Wait();
}
private static async Task DoSomething()
{
Console.WriteLine(SynchronizationContext.Current != null); // true
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // false! why ?
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,await操作员会捕获当前的信息SynchronizationContext然后将其余的异步方法发布到它.
但是,在我的应用程序中,之后SynchronizationContext.Current为null await.这是为什么 ?
编辑:
即使我自己使用SynchronizationContext它也不会被捕获,尽管它的Post功能被调用.这是我的SC:
public class MySC : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
base.Post(d, state);
Console.WriteLine("Posted");
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我使用它的方式:
var sc = new MySC();
SynchronizationContext.SetSynchronizationContext(sc); …Run Code Online (Sandbox Code Playgroud) 假设我有这个代码
ThreadPool.QueueUserWorkItem(unused =>
{
SynchronizationContext.SetSynchronizationContext(
new MyCustomSynchronizationContext());
// not reset back to null
}, null);
Run Code Online (Sandbox Code Playgroud)
当前同步上下文泄漏回线程池.如果有人再次调用ThreadPool.QueueUserWorkItem并且同一个线程用于处理其他工作项,那么该线程的当前同步上下文是否会重置为null或者它是否会保留MyCustomSynchronizationContext?
相同的答案是否适用于在线程池上执行任务的任何其他方式,例如Task.Run,BeginInvoke等?
我知道一般来说TLS没有重置,但是.NET源代码显示当前同步上下文的存储没有非常明确地定义(大多数时候它来自executioncontext但是它似乎特别适用于WinRT的一些原因).
c# asynchronous synchronizationcontext threadpool async-await
在阅读了Stephen Toub关于SynchronizationContext的文章后,我留下了一个关于这段.NET 4.5代码输出的问题:
private void btnDoSomething_Click()
{
LogSyncContext("btnDoSomething_Click");
DoItAsync().Wait();
}
private async Task DoItAsync()
{
LogSyncContext("DoItAsync");
await PerformServiceCall().ConfigureAwait(false); //to avoid deadlocking
}
private async Task PerformServiceCall()
{
LogSyncContext("PerformServiceCall 1");
HttpResponseMessage message = await new HttpClient
{
BaseAddress = new Uri("http://my-service")
}
.GetAsync("/").ConfigureAwait(false); //to avoid deadlocking
LogSyncContext("PerformServiceCall 2");
await ProcessMessage(message);
LogSyncContext("PerformServiceCall 3");
}
private async Task ProcessMessage(HttpResponseMessage message)
{
LogSyncContext("ProcessMessage");
string data = await message.Content.ReadAsStringAsync();
//do something with data
}
private static void LogSyncContext(string statementId)
{
Trace.WriteLine(String.Format("{0} {1}", statementId, …Run Code Online (Sandbox Code Playgroud) https://msdn.microsoft.com/en-us/magazine/gg598924.aspx
这是一篇很棒的文章,我知道所有细节都无法涵盖,因为这实际上涉及粘贴.NET框架的源代码.所以引用文字:
每个线程都有一个当前上下文.如果"Current"为null,则按照惯例,线程的当前上下文为"new SynchronizationContext()".
但另一方面:
默认情况下,当前的SynchronizationContext是在await点捕获的,并且此SynchronizationContext用于在await之后恢复(更确切地说,它捕获当前的SynchronizationContext, 除非它为null,在这种情况下它捕获当前的TaskScheduler)
这两个陈述相互矛盾,所以我认为这是作者做出的一些简化的结果(我很好).
有人能解释一下吗?代码可能有助于回答我的问题(查找syncCtx变量),这段代码与第二个引用相关.
假设我编写了一个依赖于async方法的库:
namespace MyLibrary1
{
public class ClassFromMyLibrary1
{
public async Task<string> MethodFromMyLibrary1(string key, Func<string, Task<string>> actionToProcessNewValue)
{
var remoteValue = await GetValueByKey(key).ConfigureAwait(false);
//do some transformations of the value
var newValue = string.Format("Remote-{0}", remoteValue);
var processedValue = await actionToProcessNewValue(newValue).ConfigureAwait(false);
return string.Format("Processed-{0}", processedValue);
}
private async Task<string> GetValueByKey(string key)
{
//simulate time-consuming operation
await Task.Delay(500).ConfigureAwait(false);
return string.Format("ValueFromRemoteLocationBy{0}", key);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我遵循了在我的图书馆里到处使用ConfigureAwait(false)(就像在这篇文章中)的建议.然后我从我的测试应用程序以同步方式使用它并获得失败:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary> …Run Code Online (Sandbox Code Playgroud) 我对以下代码的行为有几件事情(但有一件主要事情)不了解。
有人可以帮忙解释一下吗?
它实际上是非常简单的代码-只是一个常规方法调用异步方法。在异步方法中,我使用using块尝试临时更改SynchronizationContext。
在代码的不同点,我探查了当前的SynchronizationContext。
这是我的问题:
码:
public class Test
{
public void StartHere()
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
this.logCurrentSyncContext("1.1"); // Context #1
Task t = f();
this.logCurrentSyncContext("1.2"); // Context #1, why not Context #2?
t.Wait();
this.logCurrentSyncContext("1.3"); // Context #1
}
private async Task f()
{
using (new ThreadPoolSynchronizationContextBlock())
{
this.logCurrentSyncContext("2.1"); // Context #2
await Task.Delay(7000);
this.logCurrentSyncContext("2.2"); // Context is NULL, why not Context #2?
}
this.logCurrentSyncContext("2.3"); // Context #1
}
// Just show the current …Run Code Online (Sandbox Code Playgroud) 我用一个控制器和一个方法创建了一个简单的WebApi项目:
public static class DoIt
{
public static async Task<string> GetStrAsync(Uri uri)
{
using (var client = new HttpClient())
{
var str = await client.GetStringAsync(uri);
return str;
}
}
}
public class TaskRunResultController : ApiController
{
public string Get()
{
var task = Task.Run(() =>
DoIt.GetStrAsync(new Uri("http://google.com"))
);
var result = task.Result;
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
我非常了解async/await和tasks; 斯蒂芬克莱里几乎虔诚地跟随他.只是存在.Result让我焦虑,我希望这会陷入僵局.我知道这Task.Run(...)很浪费,导致在等待异步DoIt()完成时占用一个线程.
问题是这不是死锁,而是让我心悸.
我看到一些答案,如/sf/answers/2282496401/,我也观察到SynchronizationContext.Currentlambda执行时为null.但是,我也有类似的问题,问为什么上面的代码会出现死锁,而且我发现死锁ConfigureAwait(false)是在使用(不捕获上下文)的情况下发生的.Result.
是什么赋予了?
c# ×10
async-await ×6
.net ×4
asynchronous ×3
.net-3.5 ×1
asp.net ×1
task ×1
threadpool ×1
using ×1