关于C#中的lock语句的困惑

Cui*_*崔鹏飞 20 c# multithreading locking block critical-section

这来自MSDN:lock关键字确保一个线程不进入代码的关键部分,而另一个线程处于临界区.

难道一个关键部分必须是相同的关键部分

或者它的意思是:lock关键字确保一个线程不会进入代码对象保护的任何关键部分,而另一个线程处于由同一对象保护的任何关键部分.?

    class Program
{
    static void Main(string[] args)
    {
        TestDifferentCriticalSections();

        Console.ReadLine();
    }

    private static void TestDifferentCriticalSections()
    {
        Test lo = new Test();

        Thread t1 = new Thread(() =>
        {
            lo.MethodA();
        });
        t1.Start();

        Thread t2 = new Thread(() =>
        {
            lo.MethodB();
        });
        t2.Start();
    }
}

public class Test
{
    private object obj = new object();

    public Test()
    { }

    public void MethodA()
    {
        lock (obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine("A");
            }
        }
    }

    public void MethodB()
    {
        lock (obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine("B");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 64

问题是措辞混乱,到目前为止的答案也不是特别清楚.让我把这个问题改成几个问题:

(1)lock语句是否确保一次锁定语句的主体中只有一个以上的线程?

.例如:

static readonly object lock1 = new object();
static readonly object lock2 = new object();
static int counter = 0;
static object M()
{
    int c = Interlocked.Increment(ref counter);
    return c % 2 == 0 ? lock1 : lock2;
}

...
lock(M()) { Critical(); }
Run Code Online (Sandbox Code Playgroud)

两个线程可能同时位于lock语句的主体中,因为lock语句锁定了两个不同的对象.线程Alpha可以调用M()并获取lock1,然后线程Beta可以调用M()并获取lock2.

(2)假设我的lock语句总是锁定在同一个对象上,lock语句是否确保一次锁定体中只有一个"活动"线程?

是.如果你有:

static readonly object lock1 = new object();
...
lock(lock1) { Critical(); }
Run Code Online (Sandbox Code Playgroud)

然后线程Alpha可以获取锁定,线程Beta将阻塞,直到锁定可用,然后才能进入锁体.

(3)假设我有两个锁定语句,并且每次锁定语句都锁定在同一个对象上,锁定语句是否确保一次锁定的主体中只有一个"活动"线程?

是.如果你有:

static readonly object lock1 = new object();
...
static void X() 
{
    lock(lock1) { CriticalX(); }
}
static void Y() 
{
    lock(lock1) { CriticalY(); }
}
Run Code Online (Sandbox Code Playgroud)

然后,如果线程Alpha在X中并且获取锁定,并且线程Beta在Y中,则线程Beta将阻塞,直到锁定可用,然后才能进入锁体.

(4)你为什么把"主动"放在"恐慌报价"中?

提醒注意一个等待线程可能在锁体中的事实.您可以使用该Monitor.Wait方法"暂停"锁定主体中的线程,并允许阻塞的线程变为活动状态并进入该锁定主体(或锁定同一对象的其他锁定主体).等待线程将保持其"等待"状态,直到脉冲.在脉冲之后的某个时间,它重新加入"就绪"队列并阻塞,直到锁中没有"活动"线程.然后它从它停止的位置恢复.

  • 与往常一样,您的答案远远超过我的彻底性和准确性.为此,我将以赞成的方式向你淋浴. (3认同)

Chr*_*ken 5

你锁定了一个物体.如果另一个线程试图同时访问该对象标记的关键部分,它将阻塞,直到锁定被移除/完成.

例:

public static object DatabaseLck= new object();

lock (DatabaseLck) {
        results = db.Query<T>(query).ToList();
     }
Run Code Online (Sandbox Code Playgroud)

要么

lock (DatabaseLck) {
       results = db.Query<T>(string.Format(query, args)).ToList();
  }
Run Code Online (Sandbox Code Playgroud)

这些代码块中的任何一个都不能同时运行,因为它们使用相同的锁对象.如果您为每个锁定对象使用了不同的锁定对象,则它们可以同时运行.