Skip to content

线程同步 - 线程锁

🏷️ C# 学习 C#

线程锁的原理:锁住一个资源,使得应用程序在同一时刻只有一个线程访问该资源。

通俗地讲,就是让多线程变成单线程。

需要锁定的资源就是 C# 中的一个对象。在选择锁对象(同步对象)时,应当始终注意以下几点:

  1. 同步对象在需要同步的多个线程中是可见的同一个对象;

  2. 在非静态方法中,静态变量不应作为同步对象;

  3. 值类型对象不能作为同步对象;

  4. 避免将字符串作为同步对象;

  5. 降低同步对象的可见性;

编写多线程代码时,要遵循下面的一个原则:类型的静态方法应当保证线程安全性,非静态方法不需要实现线程安全

示例代码

cs
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;

namespace WaitHandleSample
{
    public partial class LockSample : Form
    {
        AutoResetEvent autoSet = new AutoResetEvent(false);
        List<string> tempList = new List<string>() { "init0", "init1", "init2" };

        public LockSample()
        {
            InitializeComponent();
        }

        private void btnStartThreads_Click(object sender, EventArgs e)
        {
            object syncObj = new object();

            Thread t1 = new Thread(() => 
            {
                // 确保等待 t2 开始之后才运行下面的代码
                autoSet.WaitOne();
                lock(syncObj)
                {
                    foreach (var item in tempList)
                    {
                        Thread.Sleep(1000);
                    }
                }
            });
            t1.IsBackground = true;
            t1.Start();

            Thread t2 = new Thread(() =>
            {
                // 通知 t1 可以执行代码
                autoSet.Set();
                // 沉睡一秒是为了确保删除操作在 t1 的迭代过程中
                Thread.Sleep(1000);
                lock (syncObj)
                {
                    tempList.RemoveAt(1);
                }
            });
            t2.IsBackground = true;
            t2.Start();

        }
    }
}

上面的代码可以正常执行结束;删除掉 lock 语句后执行,会抛出如下异常:

集合已修改;可能无法执行枚举操作。