C#线程全局配置设置的安全性

时间:2009-05-28 19:21:41

标签: c# multithreading configuration

在C#应用程序中,假设我有一个包含一些配置项的全局类,如下所示:

public class Options  
{  
    int myConfigInt;  
    string myConfigString;  
    ..etc.  
}  

static Options GlobalOptions;  

此类的成员将在不同的线程中使用:

Thread1: GlobalOptions.myConfigString = blah;

Thread2: string thingie = GlobalOptions.myConfigString;

当2个线程访问不同的成员时,使用锁来访问GlobalOptions对象也会不必要阻塞,但另一方面,为每个成员创建一个sync-object似乎也有点过头了。

另外,对全局选项使用锁定会使我的代码不那么好看; 如果我必须写

string stringiwanttouse;
lock(GlobalOptions)
{
   stringiwanttouse = GlobalOptions.myConfigString;
}

无处不在(这是线程安全的还是stringiwanttouse现在只是指向myConfigString的指针?是的,我是C#的新手......)而不是

string stringiwanttouse = GlobalOptions.myConfigString;

它使代码看起来很糟糕。

所以... 什么是确保线程安全的最佳(也是最简单!)方法?

4 个答案:

答案 0 :(得分:4)

您可以在属性中包装有问题的字段(在本例中为myConfigString),并在Get / Set中包含使用Monitor.Lock或Mutex的代码。然后,访问该属性只锁定该单个字段,并且不会锁定整个类。

编辑:添加代码

private static object obj = new object(); // only used for locking
public static string MyConfigString {
    get {
       lock(obj)
       {
          return myConfigstring;
       }
    }
    set {
       lock(obj)
       {
          myConfigstring = value;
       }
    }
}

答案 1 :(得分:3)

以下内容是在OP编辑之前编写的:

public static class Options
{
    private static int _myConfigInt;
    private static string _myConfigString;

    private static bool _initialized = false;
    private static object _locker = new object();

    private static void InitializeIfNeeded()
    {
        if (!_initialized) {
            lock (_locker) {
                if (!_initialized) {
                    ReadConfiguration();
                    _initalized = true;
                }
            }
        }
    }

    private static void ReadConfiguration() { // ... }

    public static int MyConfigInt {
        get {
            InitializeIfNeeded();
            return _myConfigInt;
        }
    }

    public static string MyConfigString {
        get {
            InitializeIfNeeded();
            return _myConfigstring;
        }
    }
    //..etc. 
}

在编辑之后,我可以说你应该做类似上面的事情,并且只在一个地方设置配置 - 配置类。这样,它将是唯一一个在运行时修改配置的类,并且仅在要检索配置选项时。

答案 2 :(得分:0)

您的配置可能是“全局”,但它们会作为全局变量公开。如果配置不更改,则应使用它们来构造需要信息的对象 - 手动或通过工厂对象。如果可以更改,则应使用监视配置文件/数据库/任何内容并实现Observer pattern的对象。

全局变量(即使是恰好是类实例的变量)也是Bad Thing™

答案 3 :(得分:0)

这里的线程安全是什么意思?它不是需要线程安全的全局对象,而是访问代码。如果两个线程在同一时刻附近写入成员变量,其中一个将“赢”,但这是一个问题吗?如果您的客户端代码依赖于全局值保持不变,直到完成某个处理单元,那么您将需要为每个需要锁定的属性创建同步对象。没有任何好办法。您可以只缓存值的本地副本以避免出现问题,但该修复程序的适用性将取决于您的具体情况。此外,默认情况下,我不会为每个属性创建一个synch对象,而是在您意识到需要它时。