【问题标题】:Why is SynchronizationContext checked for null?为什么 SynchronizationContext 检查为空?
【发布时间】:2015-11-23 09:20:35
【问题描述】:

InstallIfNeeded method 的 WindowsFormsSynchronizationContext 类,在 try 块中:

SynchronizationContext currentContext = AsyncOperationManager.SynchronizationContext;
//Make sure we either have no [....] context
//or that we have one of type SynchronizationContext

if (currentContext == null || currentContext.GetType() == typeof(SynchronizationContext))
{
...

首先,调用AsyncOperationManager.SynchronizationContext getter,并检查其返回值是否为空。这里需要检查 null 吗?

AsyncOperationManager.SynchronizationContext 的代码如下。它首先检查当前同步上下文是否为空,如果是,则创建一个新的。所以可能这个 getter 永远不会返回 null。

public static SynchronizationContext SynchronizationContext 
{
get 
{
    if (SynchronizationContext.Current == null) 
    {
        SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
    }
    return SynchronizationContext.Current;
}

【问题讨论】:

  • 该评论是无用评论的完美示例。它与代码已经明确指定的内容相呼应。
  • @usr 它检查AsyncOperationManager.SynchronizationContext(这是第二个代码 sn-p)。检查它的返回值是否为空,如果它返回SynchronizationContext.Current,那么它确实检查SynchronizationContext.Current 是否为空。

标签: c# multithreading


【解决方案1】:

这里有必要检查 null 吗?

我之前的回答忽略了SynchronizationContext.Current 实际上将基于线程而不是跨多个线程创建的事实(感谢@PerSerAl 指出这一点)。很明显你可以在代码中看到:

// Get the current SynchronizationContext on the current thread
public static SynchronizationContext Current 
{
    get      
    {
        return Thread.CurrentThread.GetExecutionContextReader().SynchronizationContext ??
               GetThreadLocalContext();
    }
}

实际上,这确实使null 检查变得多余,但它本身不会受到将来可能发生的任何未来更改的影响,以围绕SynchronizationContext 实现进行编码。

【讨论】:

  • AFAIK,SynchronizationContext.Current 是每个线程的属性,所以不需要同步,因为其他线程只能设置自己的SynchronizationContext
【解决方案2】:

使用现在的确切代码,你是对的。

但是,请查看代码的意图。关键是安装winforms上下文是安全的唯一一点是没有其他同步上下文。这对应于具有null 同步上下文或默认SynchronizationContext

同步上下文永远可能是null 在当前代码的精确版本中这一事实在很大程度上是无关紧要的。诚然,这可能不会改变,因为它是一个公共静态接口,但取决于它是完全不必要的依赖。您希望您的代码尽可能清楚地表明其意图,而此检查正是这样做的 - 同时还避免直接依赖于公共接口的内部行为。

【讨论】:

    【解决方案3】:

    这就是我所看到的(前两位与您的问题相同):

    SynchronizationContext currentContext = AsyncOperationManager.SynchronizationContext;
                //Make sure we either have no [....] context or that we have one of type SynchronizationContext
                if (currentContext == null || currentContext.GetType() == typeof(SynchronizationContext)) {
    

    然后转到:

    public static SynchronizationContext SynchronizationContext {
            get {
                if (SynchronizationContext.Current == null) {
                    SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
                }
    
                return SynchronizationContext.Current;
            }
    

    然后导致:in the line (SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

    public static void SetSynchronizationContext(SynchronizationContext syncContext)
        {
            ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
            ec.SynchronizationContext = syncContext;
            ec.SynchronizationContextNoFlow = syncContext;
        }
    

    然后它返回SynchronizationContext.Current

    public static SynchronizationContext Current 
        {
            get      
            {
                return Thread.CurrentThread.GetExecutionContextReader().SynchronizationContext ?? GetThreadLocalContext();
            }
        }
    

    哪些可能在这里结束。

    private static SynchronizationContext GetThreadLocalContext()
        {
            SynchronizationContext context = null;
    
    #if FEATURE_APPX
            if (context == null && Environment.IsWinRTSupported)
                context = GetWinRTContext();
    #endif
    
            return context;
        }
    

    如您所见,如果IsWinRTSupported 返回 false,context 可以为 null。

    根据我所看到的,空检查可能是个好主意。我不知道第一个条件 Thread.CurrentThread.GetExecutionContextReader().SynchronizationContext 是否可以返回 null 但考虑到 ?? 运算符,这是有可能的。

    【讨论】:

    • 如果SynchronizationContext.Current == null 为真,那么SetSynchronizationContext 将分配一个新的同步上下文。返回时不会是null
    • @YuvalItzchakov 绝对有可能。我没有讨论GetMutableExecutionContext() 是否与GetExecutionContextReader() 相同,但根据我在?? 上看到的情况,我想在SetSynchronizationContext 之后它可能仍然为空。我个人从未见过 SynchronizationContext 在 winforms 应用程序中为空(但始终为空,除非在控制台应用程序中手动设置),但我认为这可能是一种可能性。
    • 看到没有null 查看ec,我认为它不能,否则你会看到NullReferenceException
    • ec 是这样的:Thread.CurrentThread.GetMutableExecutionContext()Current 正在尝试获取Thread.CurrentThread.GetExecutionContextReader()。这是两个不同的方法调用,我没有检查两者是否在同一件事上运行。我怀疑你是对的,尽管它们是一样的(不需要空检查),但我没有深入挖掘。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多