当前位置:  开发笔记 > 编程语言 > 正文

线程安全使用单身成员

如何解决《线程安全使用单身成员》经验,为你挑选了2个好方法。

我有一个多个类使用的C#单例类.是通过线程安全InstanceToggle()方法访问?如果是,通过什么假设,规则等.如果不是,为什么以及如何解决它?

public class MyClass
{
    private static readonly MyClass instance = new MyClass();

    public static MyClass Instance
    {
        get { return instance; }
    }

    private int value = 0;

    public int Toggle()
    {
        if(value == 0) 
        {
            value = 1; 
        }
        else if(value == 1) 
        { 
            value = 0; 
        }

        return value;
    }
}

Orion Edward.. 28

是通过'Instance'访问'Toggle()'类threadafe吗?如果是,通过什么假设,规则等.如果不是,为什么以及如何解决它?

不,这不是线程安全的.

基本上,两个线程可以同时运行该Toggle函数,因此可能会发生这种情况

    // thread 1 is running this code
    if(value == 0) 
    {
        value = 1; 
        // RIGHT NOW, thread 2 steps in.
        // It sees value as 1, so runs the other branch, and changes it to 0
        // This causes your method to return 0 even though you actually want 1
    }
    else if(value == 1) 
    { 
        value = 0; 
    }
    return value;

您需要按照以下假设进行操作.

如果2个线程正在运行,它们可以并且将在任何点随机交错并相互交互.您可以在写入或读取64位整数或浮点数(在32位CPU上)的一半,另一个线程可以跳入并从您下面更改它.

如果2个线程永远不会访问任何共同点,那么无关紧要,但只要它们这样做,就需要防止它们踩到彼此的脚趾.在.NET中执行此操作的方法是使用锁.

您可以通过考虑以下事情来决定锁定的内容和位置:

对于给定的代码块,如果something从我的下面改变了get 的值,那会有关系吗?如果愿意,您需要something在代码的持续时间内将其锁定.

再看一遍你的例子

    // we read value here
    if(value == 0) 
    {
        value = 1; 
    }
    else if(value == 1) 
    { 
        value = 0; 
    }
    // and we return it here
    return value;

为了使它返回我们期望的内容,我们假设value在read和the之间不会改变return.为了使此假设实际上正确,您需要锁定value该代码块的持续时间.

所以你这样做:

lock( value )
{
     if(value == 0) 
     ... // all your code here
     return value;
}

然而

在.NET中,您只能锁定引用类型.Int32是一种值类型,因此我们无法锁定它.
我们通过引入"虚拟"对象,并锁定解决这个那个地方,我们会想锁定"价值".

这就是Ben Scheirman所指的.



1> Orion Edward..:

是通过'Instance'访问'Toggle()'类threadafe吗?如果是,通过什么假设,规则等.如果不是,为什么以及如何解决它?

不,这不是线程安全的.

基本上,两个线程可以同时运行该Toggle函数,因此可能会发生这种情况

    // thread 1 is running this code
    if(value == 0) 
    {
        value = 1; 
        // RIGHT NOW, thread 2 steps in.
        // It sees value as 1, so runs the other branch, and changes it to 0
        // This causes your method to return 0 even though you actually want 1
    }
    else if(value == 1) 
    { 
        value = 0; 
    }
    return value;

您需要按照以下假设进行操作.

如果2个线程正在运行,它们可以并且将在任何点随机交错并相互交互.您可以在写入或读取64位整数或浮点数(在32位CPU上)的一半,另一个线程可以跳入并从您下面更改它.

如果2个线程永远不会访问任何共同点,那么无关紧要,但只要它们这样做,就需要防止它们踩到彼此的脚趾.在.NET中执行此操作的方法是使用锁.

您可以通过考虑以下事情来决定锁定的内容和位置:

对于给定的代码块,如果something从我的下面改变了get 的值,那会有关系吗?如果愿意,您需要something在代码的持续时间内将其锁定.

再看一遍你的例子

    // we read value here
    if(value == 0) 
    {
        value = 1; 
    }
    else if(value == 1) 
    { 
        value = 0; 
    }
    // and we return it here
    return value;

为了使它返回我们期望的内容,我们假设value在read和the之间不会改变return.为了使此假设实际上正确,您需要锁定value该代码块的持续时间.

所以你这样做:

lock( value )
{
     if(value == 0) 
     ... // all your code here
     return value;
}

然而

在.NET中,您只能锁定引用类型.Int32是一种值类型,因此我们无法锁定它.
我们通过引入"虚拟"对象,并锁定解决这个那个地方,我们会想锁定"价值".

这就是Ben Scheirman所指的.



2> Thomas Watne..:

Ben指出,原始的补充不是线程安全的

使线程安全的一种简单方法是引入一个lock语句.例如.像这样:

public class MyClass
{
    private Object thisLock = new Object();
    private static readonly MyClass instance = new MyClass();
    public static MyClass Instance
    {
        get { return instance; }
    }
    private Int32 value = 0;
    public Int32 Toggle()
    {
        lock(thisLock)
        {
            if(value == 0) 
            {
                value = 1; 
            }
            else if(value == 1) 
            { 
                value = 0; 
            }
            return value;
        }
    }
}

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有