C#中的LOCK

一、LOCK概念理解

  1. 竞争同一锁的线程会互斥访问
  2. 不竞争锁的线程不受影响
  3. 加锁代码块的修改对其他遵守锁协议的线程表现为原子操作
  4. 不同于FreeRTOS中的临界区,加锁之后其他的线程还是可以正常运行,只有竞争同一把锁的线程才会阻塞
  5. 功能等同于FreeRTOS中的互斥锁,如果A线程加锁,其他线程还要访问这一把锁,就会被阻塞,但是不影响不访问这一把锁的线程
  6. 他和FreeRTOS中的二值信号量最大的区别就是,lock规定,谁加的锁就只能是谁释放,但是二值信号量就是所有线程都可以解锁和加锁,这一点lock和互斥锁一样。

二、实例说明

cs 复制代码
using System;
using System.Threading;

class LockExample
{
    // 共享资源
    private static int _value = 0;
    private static readonly object _lock = new object();

    static void Main()
    {
        // 线程1:频繁修改共享资源
        new Thread(() => {
            while (true)
            {
                _value = 0;
                
                lock (_lock)
                {
                    _value = 1;  // 状态A
                    Thread.Sleep(100);
                    _value = 2;  // 状态B
                    Thread.Sleep(100);
                    _value = 3;  // 状态A
                }
            }
        }).Start();

        // 线程2:尝试获取同一把锁
        new Thread(() => {
            while (true)
            {
                lock (_lock)  // 会阻塞直到获取锁
                {
                    Console.WriteLine($"Thread2 sees: {_value}");
                }
                Thread.Sleep(50);
            }
        }).Start();

        // 线程3:不竞争锁,直接读取共享资源
        new Thread(() => {
            while (true)
            {
                Console.WriteLine($"Thread3 sees: {_value}"); // 可能看到中间状态!
                Thread.Sleep(50);
            }
        }).Start();
    }
}

观看上述的代码,

由于线程1和线程2竞争同一把锁,所以导致这两个锁中的代码只能被互斥访问,即线程2中输出的value值只能是0或者3,但是基本不会输出0,因为将value=0后马上就执行锁的内容。

线程3没有遵守锁的协议,因此它可以输出1,2,3,0,这些输出的结果都是随机的。