Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Enum.TryParse-它是线程安全的吗?_C#_.net_.net 4.0_Enums_Tryparse - Fatal编程技术网

C# Enum.TryParse-它是线程安全的吗?

C# Enum.TryParse-它是线程安全的吗?,c#,.net,.net-4.0,enums,tryparse,C#,.net,.net 4.0,Enums,Tryparse,我试图弄清楚.NET4.0的Enum.TryParse是否是线程安全的 源代码(反编译)是: 如果另一个线程在其被设置为默认值之后,在其被设置为解析值之前访问了结果,该怎么办 [编辑] 在佐伊德伯格的回答之后,我想重新表述一下这个问题 我想问题是,Enum.TryParse是否是“事务性的”(或原子性的) 假设我有一个静态字段,并将其传递到Enum.TryParse: public static SomeEnum MyField; .... Enum.TryParse("Value", out

我试图弄清楚.NET4.0的Enum.TryParse是否是线程安全的

源代码(反编译)是:

如果另一个线程在其被设置为默认值之后,在其被设置为解析值之前访问了结果,该怎么办

[编辑] 在佐伊德伯格的回答之后,我想重新表述一下这个问题

我想问题是,Enum.TryParse是否是“事务性的”(或原子性的)

假设我有一个静态字段,并将其传递到Enum.TryParse:

public static SomeEnum MyField;
....
Enum.TryParse("Value", out MyField);
现在,当执行TryParse时,另一个线程访问MyField。TryParse会将MyField的值更改为SomeEnum的默认值一段时间,然后才将其设置为已解析的值


这不一定是我代码中的错误。我希望Enum.TryParse将MyField设置为已解析的值,或者根本不接触它,而不是将其用作其临时字段。

结果与其他所有局部变量和参数一样,是每次调用的结果。by ref参数的线程安全性要描述得复杂一些,但是:在每一种正常的使用中,这都不会是一个问题。我可以强制一个有风险的场景(由于副裁判传球),但这是一个人为的例子

典型用法:

SomeEnumType foo;
if(Enum.TryParse(s, true, out foo)) {...}
它是完全安全的

以下内容稍微复杂一些:

var objWithField = new SomeType();
// thread 1:
{
    Enum.TryParse(x, true, out objWithField.SomeField));
}
// thread 2:
{
    Enum.TryParse(y, true, out objWithField.SomeField));
}
并且不是线程安全的,但其原因比您在问题中描述的要微妙得多。

是的-是的

您反编译的方法中根本没有共享状态

如果另一个线程调用同一个方法,它将获得它自己的所有局部变量的副本,
result
由调用者传入


如果
result
是一个类级变量,那么这将是一个问题,但这很好。

真正的问题不是TryParse是否线程安全,而是使用它的代码(您的代码)是否线程安全。如果传入结果变量,然后让另一个线程在没有互斥保护的情况下访问它,那么可能会有问题,但问题会出现在代码中。

结果(以及它引用的变量)可能会变成默认值(T),尽管字符串值包含一个不同的枚举值,如果这是您的意思的话

请尝试以下程序:

public enum FooBar
{
    Foo = 0,
    Bar
}

internal class Program
{
    private static FooBar fb = FooBar.Bar;

    private static void Main()
    {
        new Thread(() =>
                       {
                           while (true)
                           {
                               if (Program.fb == FooBar.Foo) // or try default(FooBar), which is the same
                               {
                                   throw new Exception("Not threadsafe");
                               }
                           }
                       }).Start();

        while (true)
        {
            if (!Enum.TryParse("Bar", true, out fb) || fb == FooBar.Foo)
            {
                throw new Exception("Parse error");
            }
        }
    }
}

它迟早(可能更早)会抛出“非线程安全”异常。

警告
result
是按ref进行的,因此虽然指针的本地副本确实是隔离的,但底层值是按ref进行的,并且存在风险,但仅在非常人为的示例中。我接受您的观点。请注意,在这种情况下-
result
是一个结构,这意味着您无论如何都不能修改任何人的副本,不是吗?因为它是按ref(
out
)的,这正是我们可以修改其他人版本的原因:只有一个值(由ref传递的结构不会被复制;而是发送一个指向该值的指针)啊,是的,当然特别是因为它是通过引用传递的。这就是我的问题的真正意思——我将尝试修改这个问题。谢谢。其他.NET TryParse方法似乎也使用您的ref变量作为自己的临时存储。这不应该被认为是微软代码中的一个bug吗?当你要求将一个变量设置为一个值时,你通常不会期望它在被设置之前经历许多其他的状态。它被记录为线程安全的吗?如果不是,那么不管它是否真的是,您都不应该依赖它是线程安全的。
var objWithField = new SomeType();
// thread 1:
{
    Enum.TryParse(x, true, out objWithField.SomeField));
}
// thread 2:
{
    Enum.TryParse(y, true, out objWithField.SomeField));
}
public enum FooBar
{
    Foo = 0,
    Bar
}

internal class Program
{
    private static FooBar fb = FooBar.Bar;

    private static void Main()
    {
        new Thread(() =>
                       {
                           while (true)
                           {
                               if (Program.fb == FooBar.Foo) // or try default(FooBar), which is the same
                               {
                                   throw new Exception("Not threadsafe");
                               }
                           }
                       }).Start();

        while (true)
        {
            if (!Enum.TryParse("Bar", true, out fb) || fb == FooBar.Foo)
            {
                throw new Exception("Parse error");
            }
        }
    }
}