多线程软件设计

本文关键字:软件 多线程 | 更新日期: 2023-09-27 18:35:11

问题,假设我有线程 A 和线程 B,它们都需要访问单例对象及其属性。

目前,单例如下所示。

public class Singleton{
        #region fields
        private static Singleton singletonObject;
        private double value1= 0;
        private double value2= 0;
        private double value3= 0;
        private double value4= 0;
        private object locker = null;
        #endregion
        // private constructor. This will avoid creating object using new keyword
        private Singleton() {
            locker = new object();
        }
        // public method which will be called
        public void GetName() {
            Console.WriteLine("singleton Object");
        }
        public static Singleton Instance() {
            // this object will be used with lock, so that it will be always one thread which will be executing the code
            object instanceLocker = new object();
            // put a lock on myObject. We won't be able to use singleTonObject becuase it will be null. lock is to make the object thread safe.
            // lock can't be worked with null objects.
            lock (instanceLocker) {
                // check whether the instance was there. If it's not there, then create an instance.
                if (singletonObject == null) {
                    singletonObject = new Singleton();
                }
            }
            return singletonObject;
        }
        public double Value1 { get { lock (locker) { return value1; } } set { lock (locker) { value1= value; } } }
        public double Value2 { get { lock (locker) { return value2; } } set { lock (locker) { value2= value; } } }
        public double Value3 { get { lock (locker) { return value3; } } set { lock (locker) { value3= value; } } }
        public double Value4 { get { lock (locker) { return value4; } } set { lock (locker) { value4= value; } } }

    }

我的问题。与其具有线程安全属性,还有更好的方法吗?

谢谢

多线程软件设计

目前您的代码已完全损坏。您正在创建一个要在每次调用期间锁定的新对象。没有其他线程会知道它,所以它完全没有意义。

不要费心试图以聪明的方式修复它。只需在静态变量初始值设定项中初始化它:

private static Singleton singletonObject = new Singleton();

很好,很简单。

有关在 C# 中实现单一实例模式(包括在 .NET 4 中使用Lazy<T>)的详细信息,请参阅我关于该主题的文章。

除了要

创建一个新对象来锁定每次调用之外,还有另一个基本问题:即使你确实有相同的对象,你仍然没有真正保护任何东西。

在将Value1初始化为 9 的行的某个地方:

Singleton.Instance().Value1 = 9;

现在假设您有两个线程执行此代码:

public void Foo()
{
    Singleton.Instance().Value1++;
    if(Singleton.Instance().Value1==10.0)
    {
         Singleton.Instance().Value2 = 20.0;
    }
    else
    {
         Singleton.Instance().Value3 = 30.0;
    }
}

线程 A 调用 Value1++ 并将值 1 递增到 10.0线程 B 调用 Value1++,现在值 1 为 11.0线程 A 检查值 1 是否为 10.0 ->返回 false!线程 A 将Value3设置为 30线程 B 也将Value3设置为 30。

这只是一个非常简单的示例,其中锁定属性不会保护您,因为外部代码无法保证读取或写入内容的顺序。线程 A 和线程 B 可能会执行许多其他订单,这将导致完全不同的结果。

此行为可能是可以的,因为您可以让 Singleton 类的用户负责确保在类外部正确操作,但通常您应该注意这一点。仅锁定属性不会消除读/写争用。

您使用的是 .NET 4.0 吗?可以使用 Concurrent 集合进行线程安全活动,而不是锁定。