Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.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# 实例构造函数设置静态成员,它是线程安全的吗?_C#_.net_Multithreading_Thread Safety - Fatal编程技术网

C# 实例构造函数设置静态成员,它是线程安全的吗?

C# 实例构造函数设置静态成员,它是线程安全的吗?,c#,.net,multithreading,thread-safety,C#,.net,Multithreading,Thread Safety,我正在重新分解一些代码,并想知道如何在实例构造函数中使用锁 public class MyClass { private static Int32 counter = 0; private Int32 myCount; public MyClass() { lock(this) { counter++; myCount = counter; } } } lock(lockObj

我正在重新分解一些代码,并想知道如何在实例构造函数中使用

public class MyClass {

    private static Int32 counter = 0;
    private Int32 myCount;

    public MyClass() {

        lock(this) {
            counter++;
            myCount = counter;
        }
    }
}
lock(lockObj){}
请确认

  • 实例构造函数是线程安全的
  • lock语句阻止访问该代码块,而不是静态“计数器”成员
  • 如果原始程序员的目的是让每个实例都知道其“计数”,那么我如何同步对“计数器”成员的访问,以确保另一个线程不是新的“正在使用
    MyClass
    ,并在设置计数之前更改计数


    仅供参考-本课程不是单身学生。实例必须知道它们的数量。

    我猜这是针对单例模式或类似模式的。您要做的不是锁定对象,而是在修改计数器时锁定计数器

    private static int counter = 0;
    private static object counterLock = new Object();
    
    lock(counterLock) {
        counter++;
        myCounter = counter;
    }
    
    因为您当前的代码有点多余。特别是在构造函数中,只有一个线程可以调用构造函数,而在方法中,它可以跨线程共享,并且可以从共享的任何线程访问


    从代码中我可以看出,您正在尝试为对象提供创建时的当前计数。因此,使用上述代码,计数器将在本地更新和设置时被锁定。因此,所有其他构造函数都必须等待计数器释放。

    您可以使用另一个静态对象锁定它

    private static Object lockObj = new Object();
    
    并将此对象锁定在构造函数中

    public class MyClass {
    
        private static Int32 counter = 0;
        private Int32 myCount;
    
        public MyClass() {
    
            lock(this) {
                counter++;
                myCount = counter;
            }
        }
    }
    
    lock(lockObj){}
    
    但是,我不确定是否存在由于
    .NET
    中的编译器优化而应该处理的情况,就像java的情况一样我认为如果您修改包含计数(显然是使用线程安全方法),您会很好:)

    编辑 废话我不小心删除了

    我不确定实例构造函数是否是线程安全的,我记得在一本设计模式书中读到过这方面的内容,您需要确保在实例化过程中锁定到位,这完全是因为..

    @

    仅供参考,这个类可能不是单例,我需要访问不同的实例。他们必须简单地保持计数。您会将单例模式的哪一部分更改为执行“计数器”递增

    或者,您是否建议我公开一个静态方法,用于构造阻止对代码的访问,该代码使用锁递增并读取计数器

    public MyClass {
    
        private static Int32 counter = 0;
        public static MyClass GetAnInstance() {
    
            lock(MyClass) {
                counter++;
                return new MyClass();
            }
        }
    
        private Int32 myCount;
        private MyClass() {
            myCount = counter;
        }
    }
    
    @阿贾马斯特里安

    我不是说您应该使用singleton模式本身,而是采用它封装实例化过程的方法

    i、 e

    • 将构造函数设为私有
    • 创建一个返回类型的静态实例方法
    • 在静态实例方法中,在实例化之前使用lock关键字
    • 实例化该类型的新实例
    • 增加计数
    • 解锁并返回新实例
    编辑 我遇到了一个问题,你怎么知道计数什么时候下降了

    重新编辑
    考虑一下,您可以向析构函数添加代码,调用另一个静态方法来减少计数器:D

    如果您只是增加一个数字,那么就有一个特殊的类(联锁)用于此

    联锁增量法

    递增指定变量并将结果存储为原子操作

    有关线程最佳实践的更多信息


    最有效的方法是使用联锁增量操作。它将一次递增计数器并返回静态计数器的新设置值(原子)

    在最初的示例中,lock(this)语句不会产生预期效果,因为每个实例都有不同的“this”引用,因此多个实例可能同时更新静态成员

    在某种意义上,构造函数可以被认为是线程安全的,因为在构造函数完成之前,对正在构造的对象的引用是不可见的,但这对保护静态变量没有任何好处


    (迈克·沙尔首先得到了联锁位)

    在构造函数中“锁”是无用的吗?我需要用静态方法锁定对静态“计数器”的访问权限,否则我无法确定还有谁在别处读/写它。@anthony:哪个锁没用?对
    的锁定是无用的,因为没有其他人可以引用
    来锁定它。
    计数器上的锁(参见上文)是正确的。减少计数器将导致两次分发数字。我认为原始程序员的意图是在创建时保持一个“总数”。计数似乎不用于跟踪与“当前实例”有关的任何内容。实际上,这是示例中最好的部分。ctor中的锁(this)非常好,因为“this”还没有返回给任何其他人,所以死锁发生的范围为零。@Quibblesome,但它不起作用,因为这是问题所在。如果两个线程同时运行
    new MyClass()
    ,则一个线程将锁定对其intance的引用,另一个线程将锁定其实例。由于这些是不同的引用,锁不会锁定任何内容,线程也不会互相等待,增量可能会出错。仅供参考,如果要锁定静态字段,可以执行
    lock(typeof(MyClass)){…}
    -请参阅