使用 Monitor 类

3
我想询问一些关于在.Net中使用Monitor类的问题。
为了理解这些问题,请查看以下代码。
public class MyClass
{
    private List<int> _MyCollection = new List<int>();

    public void GetLock()
    {
        Monitor.Enter(_MyCollection);
    }

    public void ReleaseLock()
    {
        Monitor.Exit(_MyCollection);
    }

    public void UpdateCollection(/*anyparam*/)
    {
        //update collection without lock on collection
    }
}

public class MyAppMain
{
    private static MyClass myclass = new MyClass();

    public static void main(args)
    {
        try
        {
            myclass.GetLock();

            //an operation that does not do any update on myclass but wanted 
            //to ensure that the collection within myclass never update
            //while its doing following opetion

            //Do somthing
        }
        finally
        {
            myclass.ReleaseLock();
        }
    }
}

这是使用监视器的正确方式吗?我需要使用Pulse或PulseAll来通知等待线程,如果需要的话,Exit函数应该在之前还是之后执行?

谢谢 Mubashar


除非您对线程有比.NET线程更丰富的经验,否则我会认真考虑在没有锁定的情况下更新集合。 - MaxGuernseyIII
2个回答

2

是的,你对Monitor的使用是正确的。

话虽如此,你可以使用lock语句使代码更加简洁:

public static void main(args)
{
    lock(myclass)
    {
    }
}

实际上,如果您将我的List<int>替换为List<List<int>>并且使用Get Lock和Release Lock仅在主List中的特定List<int>上工作,则锁语句将不适用。简而言之,我不想锁定整个集合对象,而是使用GetLock和ReleaseLock函数锁定其中的一部分。 - Mubashar
1
@MubasharAhmad - lockиҜӯеҸҘеҸҜд»ҘдҪҝз”Ёд»»дҪ•Monitor.EnterеҸҜд»ҘдҪҝз”Ёзҡ„еҜ№иұЎгҖӮеӣ жӯӨпјҢжӮЁеҸҜд»Ҙеҗ‘MyClassж·»еҠ дёҖдёӘеҮҪж•°public Object GetLockTarget() { return ...; }пјҢ然еҗҺйҖҡиҝҮжү§иЎҢlock(myclass.GetLockTarget())жқҘй”Ғе®ҡе®ғгҖӮ - R Samuel Klatchko

2
在finally块中获取和释放锁是正确的。我建议在try块开始前先获取锁,但不会对程序造成伤害,除非获取锁时发生异常。
针对你实际想要做的事情,你需要重新思考你的目标。根据性能是否是一个问题,你可以考虑使用ReaderWriterLock。如果争用很少,请考虑锁定每个操作,但是可以使用自旋锁——对于不容易重叠但可能花费较多时间的操作来说,这种方法非常便宜。
此外,如果你不能确保只有一个线程会更新集合,请重新考虑不加锁更新集合的概念。

  1. 你在获取锁之前使用Try是正确的,我通常也会像你建议的那样做。
  2. 对于使用ReaderWriterLockSlim,你再次是正确的,自从我发布了这篇文章后,我正在考虑它;)。 实际上,上面的代码并不完全是我想要做的,只是简单地反映了一下。
  3. 抱歉我的阅读能力不好,我无法理解你所说的“Also:”后面的内容。
- Mubashar
  1. 简单来说,我不知道你在线程方面的经验水平如何。如果你没有非常强的线程背景,那么在你的示例代码中加上注释//update collection without lock on collection意味着你正在走一条非常危险的道路,除非你没有告诉我们有关你的类将如何使用的上下文信息。
- MaxGuernseyIII
哎呀,实际上我忘记在//做某事之后添加UpdateCollection函数调用了,因为锁已经被调用GetLock函数的调用者占用了。 - Mubashar
你没有提到Pulse/PluseAll函数,使用Monitor时在Exit函数后调用它是强制性的吗? - Mubashar
1
不。Pulse/PulseAll必须在Exit()之前调用,并且只有在其他线程调用了Wait()时才需要调用它们。 - MaxGuernseyIII

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接