C# Lock

本文详细探讨了C#中锁的使用方式,包括单一线程对同一锁的重复获取与释放、不同线程间的锁竞争导致的死锁现象以及如何避免这些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.在不同的代码片段使用同一个锁,这两个代码片段只能被获得锁的线程访问,其他线程不能访问。

namespace 同一个锁测试
{
    class Program
    {
        private static object obj1 = new object();
        public static int count = 0;
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() =>
            {
                while (true)
                {
                    Function1();
                }
            });
            Thread t2 = new Thread(() =>
            {
                while (true)
                {
                    Function2();
                }
            });
            t1.Start();
            t2.Start();
        }
        private static void Function1()
        {
            lock (obj1)
            {
                count++;

                Console.WriteLine("thread1:count is " + count);
                Thread.Sleep(500);

            }
        }
        private static void Function2()
        {
            lock (obj1)
            {              
                count++;
                Console.WriteLine("thread2:count is " + count);
                Thread.Sleep(500);
            }
        }
    }
}

输出结果:

从结果可以看到:Function1和Function2函数同一时刻,不能被不同线程同时执行。说明同一个锁被用于多处时,只能由获得锁的线程访问,其他线程不能访问。
2.死锁的发生:当两段代码使用锁的顺序不一致时,容易发生死锁

namespace LockTest
{
    class Program
    {
        private static object obj1 = new object();
        private static object obj2 = new object();
        public static int count = 0;
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() =>
            {
                while (true)
                {
                    Function1();
                }
            });
            Thread t2 = new Thread(() =>
            {
                while (true)
                {
                    Function2();
                }
            });
            t1.Start();
            t2.Start();
        }
        private static void Function1()
        {
            lock (obj1)
            {

                lock (obj2)
                {
                    count++;
                    Console.WriteLine("thread1:count is "+count);
                }
            }
        }
        private static void Function2()
        {
            lock (obj2)
            {

                lock (obj1)
                {
                    count++;
                    Console.WriteLine("thread2:count is " + count);
                }
            }
        }
    }

}

运行结果如下:
这里写图片描述
可以看到输出了一句话然后就卡住了。
原因:线程t1进入Function1方法后获得obj1的锁,同一时刻,线程t2进入Function2方法获得obj2的锁。然后t1等待获得了obj2的锁才能执行(obj2的锁被t2占住了),t2等待获得obj1的锁才能执行(obj1的锁被t1占住了),所以两个互相等待对方释放锁,结果出现无限的等待的死锁现象。
3.同一个线程可以获得同一个锁多次,但是也必须释放多次,释放次数必须和获得次数相同
使用lock时,当进入“{”时获得锁,退出“}”时自动释放锁,不需要我们去关心锁的释放,好比我们使用using实现了IDispose接口的对象一样。但是某些情况下我们要使用Monitor.Enter/Monitor.Exit方法。

namespace Lock同一个对象多次释放一次
{
    class Program
    {
        private static object obj1 = new object();
        public static int count = 0;
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() =>
            {
                while (true)
                {                    
                    Function();
                    Thread.Sleep(500);
                }
            });
            t1.Name = "t1";
            Thread t2 = new Thread(() =>
            {
                while (true)
                {
                    Function();
                    Thread.Sleep(500);
                }
            });
            t2.Name = "t2";

            t1.Start();
            t2.Start();
        }
        private static void Function()
        {
            Monitor.Enter(obj1);
            Monitor.Enter(obj1);
            count++;
            Console.WriteLine("current thread is " + Thread.CurrentThread.Name);
            Console.WriteLine("count is " + count);
            Monitor.Exit(obj1);
            //Monitor.Exit(obj1);
        }
    }
}

注意:最后一句Monitor.Exit(obj1)被注释掉了,运行结果如下:
这里写图片描述
Function函数只能被同一个线程执行说明线程t1获得了锁没有释放,所以t2执行不了。并且每多执行一次Function函数,t1就少释放obj1一次。
当将最后的Monitor.Exit(obj1)的注释取消后,代码如下:

 private static void Function()
        {
            Monitor.Enter(obj1);
            Monitor.Enter(obj1);
            count++;
            Console.WriteLine("current thread is " + Thread.CurrentThread.Name);
            Console.WriteLine("count is " + count);
            Monitor.Exit(obj1);
            Monitor.Exit(obj1);
        }

再次运行结果如下:
这里写图片描述
结果恢复正常,说明了上述的观点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值