在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;
它使代码看起来很糟糕。
所以... 什么是确保线程安全的最佳(也是最简单!)方法?
答案 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对象,而是在您意识到需要它时。