Skip to main content
 首页 » 编程设计

c#之使 MTA 中的锁定更容易

2024年02月24日35jiqing9006

在多线程代码中,当一个实例可能被多个线程读取或写入时,它们需要被锁定以安全地执行这些操作。

为了避免重复创建要锁定的对象和通过代码编写一堆锁定语句,我创建了一个通用类来处理锁定。

从概念上讲,我是否遗漏了什么?这应该有效,对吧?

public class Locked<T> where T : new() 
{ 
    private readonly object locker = new object(); 
 
    private T value; 
 
    public Locked() 
        : this(default(T)) 
    { } 
 
    public Locked(T value) 
    { 
        this.value = value; 
    } 
 
    public T Get() 
    { 
        lock (this.locker) 
        { 
            return this.value; 
        } 
    } 
 
    public void Set(T value) 
    { 
        lock (this.locker) 
        { 
            this.value = value; 
        } 
    }     
} 

还有一个在类里面使用它的例子:

private Locked<bool> stopWorkerThread = new Locked<bool>(); 
 
public void WorkerThreadEntryPoint() 
{ 
    while (true) 
    { 
        if (this.stopWorkerThread.Get()) 
        { 
            break; 
 
} 

另外,我如何以自动化方式测试这样的东西(例如创建单元测试)?

最后,我可以做些什么来实现++ 和 -- 运算符,以避免这种情况:

        this.runningThreads.Set(this.runningThreads.Get() + 1); 

请您参考如下方法:

仅在获取/设置期间锁定;当然,在许多常见情况下,这无论如何都是原子的,仅仅是由于数据大小。

然而,实际上大多数锁需要跨越的范围不止于此,就像仅在 Add 等上锁定集合并没有多大帮助一样 - 调用者通常需要一个锁来跨越“它在那里吗?如果所以更新,否则添加“序列。

对于像 bool 这样简单的东西,“volatile”可能会更简单地解决问题 - 特别是如果它只是为了循环退出。

您可能还想考虑 [MethodImpl(MethodImplOptions.Synchronized)] - 尽管我个人更喜欢私有(private)锁对象(就像您使用的那样)以防止外部人员锁定对象的问题(上面使用“this”作为锁)。

对于此单元测试,您首先需要一些东西来证明它已损坏 - 这将很难,因为操作非常小(并且对于大多数数据类型来说已经是原子的)。它避免的另一件事(volatile 也修复)是在寄存器中缓存,但这又是一种优化,很难强制证明它被破坏了。

如果您对锁包装器感兴趣,您可以考虑像 this 这样的现有代码.