c#中lock的经典示例

news/2025/2/9 4:09:31 标签: 开发语言, c#

lock 是 C# 中的一种用于同步线程执行的机制,它帮助确保多个线程在访问共享资源时不会发生冲突或数据损坏。其作用是通过给临界区(即多线程访问共享资源的代码段)加锁,使得在同一时刻只能有一个线程进入执行该代码段。

1、lock 的工作原理

  • 加锁和解锁:当一个线程进入一个 lock 块时,它会获取一个对象的锁(通常是该块代码所属对象的锁)。其他线程在该锁被释放之前无法进入同一 lock 块。当线程退出 lock 块时,它会自动释放锁。
  • 防止线程冲突:lock 主要用于保护共享数据,避免多个线程同时访问或修改共享资源,造成数据不一致或程序崩溃的问题。

2、语法

lock (someObject)
{
    // 临界区代码:只有获得锁的线程能进入
    // 共享资源的操作代码
}

3、关键点

  1. someObject:lock 语句后面必须跟一个对象,这个对象用于在多个线程之间进行同步。通常使用类的实例对象,或是使用 this 来加锁当前对象。someObject 作为锁,通常不会使用原始类型数据或者是可变的对象。
  2. 自动解锁:一旦线程执行完 lock 块中的代码,锁就会自动释放,其他线程就有机会获取锁并进入临界区。
  3. 死锁:如果两个或多个线程相互等待对方释放锁,可能会导致死锁(即程序进入永久等待状态)。因此,设计时要注意锁的获取顺序和策略,避免这种情况。

4、lock 的实际应用

lock 经常用于以下场景:

  • 操作共享数据:当多个线程需要操作同一资源时,通过 lock 来确保只有一个线程能够访问该资源,从而避免数据竞争。
  • 数据库或文件访问:当多个线程需要访问数据库或文件时,需要同步这些访问操作,以防止数据损坏。

5、lock的经典示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Demo
{
    class Program
    {
        int num = 10;//设置当前总票数
        void Ticket()
        {
            while (true)//设置无限循环
            {
                Console.WriteLine("  " + Thread.CurrentThread.Name + " lock前");//申请lock
                lock (this)//锁定代码块,以便线程同步
                {
                    Console.WriteLine("    " + Thread.CurrentThread.Name + " lock中");//获得lock
                    if (num > 0)//判断当前票数是否大于0
                    {
                        Console.WriteLine("    " + Thread.CurrentThread.Name + " Sleep(100)");
                        Thread.Sleep(100);//使当前线程休眠100毫秒
                        Console.WriteLine("    " + Thread.CurrentThread.Name + "----票数" + num--);//票数减1
                    }
                    else
                    {
                        Console.ReadLine();
                    }
                }
                Console.WriteLine("  " + Thread.CurrentThread.Name + " lock后");//释放lock
            }
        }
        static void Main(string[] args)
        {
            Program p = new Program();//创建对象,以便调用对象方法
            Thread tA = new Thread(new ThreadStart(p.Ticket));//分别实例化4个线程,并设置名称
            tA.Name = "线程A";
            Thread tB = new Thread(new ThreadStart(p.Ticket));
            tB.Name = "线程B";
            Thread tC = new Thread(new ThreadStart(p.Ticket));
            tC.Name = "线程C";
            Thread tD = new Thread(new ThreadStart(p.Ticket));
            tD.Name = "线程D";
            tA.Start(); //分别启动线程
            Console.WriteLine("tA.Start");
            tB.Start();
            Console.WriteLine("tB.Start");
            tC.Start();
            Console.WriteLine("tC.Start");
            tD.Start();
            Console.WriteLine("tD.Start");
            Console.ReadLine();
        }
    }
}

运行结果

tA.Start			    ->main中,线程A启动
  线程A lock前		    ->	进入线程A,线程A申请lock
    线程A lock中		->	    线程A获得lock
    线程A Sleep(100)	->		线程A休眠
tB.Start				->main中,线程B启动				 ->这里可以看到线程休眠程序,会返回main
  线程B lock前		    ->	进入线程B,线程B申请lock
tC.Start				->main中,线程C启动
  线程C lock前		    ->	进入线程C,线程C申请lock
tD.Start				->main中,线程D启动
  线程D lock前		    ->	进入线程D,线程D申请lock
    线程A----票数10		->		线程A休眠结束,线程A运行
  线程A lock后		    ->	线程A释放lock
  线程A lock前		    ->	线程A申请lock
    线程B lock中	    ->	    线程B获得lock
    线程B Sleep(100)	->		线程B休眠
    线程B----票数9		->		线程B休眠结束,线程B运行	->这里可以看到线程休眠,不会释放lock
  线程B lock后		    ->	线程B释放lock
  线程B lock前		    ->	线程B申请lock
    线程C lock中	    ->	    线程C获得lock
    线程C Sleep(100)	->		线程C休眠
    线程C----票数8		->		线程C休眠结束,线程C运行
  线程C lock后		    ->	线程C释放lock
  线程C lock前		    ->	线程C申请lock
    线程D lock中
    线程D Sleep(100)
    线程D----票数7
  线程D lock后
  线程D lock前
    线程A lock中
    线程A Sleep(100)
    线程A----票数6
  线程A lock后
  线程A lock前
    线程B lock中
    线程B Sleep(100)
    线程B----票数5
  线程B lock后
  线程B lock前
    线程C lock中
    线程C Sleep(100)
    线程C----票数4
  线程C lock后
  线程C lock前
    线程D lock中
    线程D Sleep(100)
    线程D----票数3
    线程A lock中
    线程A Sleep(100)
  线程D lock后
  线程D lock前
    线程A----票数2
  线程A lock后
  线程A lock前
    线程B lock中
    线程B Sleep(100)
    线程B----票数1
  线程B lock后
  线程B lock前
    线程C lock中

6、 死锁的经典示例

using System;
using System.Threading;
 
class Program
{
    private readonly object lock1 = new object();
    private readonly object lock2 = new object();
 
    public void Thread1()
    {
        lock (lock1)
        {
            Console.WriteLine("Thread 1: Acquired lock1");
            Thread.Sleep(1000);  // 模拟一些工作
            Console.WriteLine("Thread 1: Trying to acquire lock2");
            lock (lock2)
            {
                Console.WriteLine("Thread 1: Acquired lock2");
            }
        }
    }
 
    public void Thread2()
    {
        lock (lock2)
        {
            Console.WriteLine("Thread 2: Acquired lock2");
            Thread.Sleep(1000);  // 模拟一些工作
            Console.WriteLine("Thread 2: Trying to acquire lock1");
            lock (lock1)
            {
                Console.WriteLine("Thread 2: Acquired lock1");
            }
        }
    }
 
    static void Main(string[] args)
    {
        Program p = new Program();//创建对象,以便调用对象方法
 
        // 创建两个线程
        Thread t1 = new Thread(p.Thread1);
        Thread t2 = new Thread(p.Thread2);
 
        // 启动线程
        t1.Start();
        t2.Start();
 
        // 等待线程结束
        t1.Join();
        t2.Join();
    }
}

运行结果

Thread 1: Acquired lock1
Thread 2: Acquired lock2
Thread 1: Trying to acquire lock2
Thread 2: Trying to acquire lock1


http://www.niftyadmin.cn/n/5845501.html

相关文章

第五十八章 Linux INPUT 子系统实验

imx6ull-alientek-emmc.dts &#xff08;使用第四十九章的设备树文件即可&#xff09; keyinput.c #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include…

GitPuk快速安装配置教程(入门级)

GitPuk是一款国产开源免费的代码管理工具&#xff0c;工具简洁易用&#xff0c;开源免费&#xff0c;本文将讲解如何快速安装和配置GitPuk&#xff0c;以快速入门上手。 1、安装 支持 Windows、Mac、Linux、docker 等操作系统。 1.1 Linux安装&#xfeff; 以下以Centos7安装…

unity学习31:Video Player 视频播放相关基础

目录 1 新增Video Player的 component 2 导入视频到Asset里 3 拖入到 video player的 video clip里去即可 4 渲染模式 4.1 多种渲染模式 4.2 如果选择 Render Texture模式 4.3 然后把Render Texture 拖到游戏里的 gameObject上面 5 在UI上显示 5.1 创建UI 5.2 在UI上…

深入解析:Jsoup 库的多功能应用场景

Jsoup 是一个强大的 Java 库&#xff0c;主要用于解析和操作 HTML 文档。它不仅广泛应用于网络爬虫和数据抓取&#xff0c;还在网页内容分析、数据清洗与处理、自动化测试等多个领域有着广泛的应用。本文将详细介绍 Jsoup 库的多种用途&#xff0c;并提供具体的代码示例。 一、…

Fiddler Classic(HTTP流量代理+半汉化)

目录 一、关于Fiddler (一) Fiddler Classic (二) Fiddler Everywhere (三) Fiddler Everywhere Reporter (四) FiddlerCore (五) 总结 二、 软件安全性 1. 软件安装包 2. 软件汉化dll 三、安装与半汉化 1. 正常打开安装包点击下一步安装即可&#xff0c;安装路径自…

【提示词工程】探索大语言模型的参数设置:优化提示词交互的技巧

在与大语言模型(Large Language Model, LLM)进行交互时,提示词的设计和参数设置直接影响生成内容的质量和效果。无论是通过 API 调用还是直接使用模型,掌握模型的参数配置方法都至关重要。本文将为您详细解析常见的参数设置及其应用场景,帮助您更高效地利用大语言模型。 …

【重新认识C语言----结构体篇】

目录 -----------------------------------------begin------------------------------------- 引言 1. 结构体的基本概念 1.1 为什么需要结构体&#xff1f; 1.2 结构体的定义 2. 结构体变量的声明与初始化 2.1 声明结构体变量 2.2 初始化结构体变量 3. 结构体成员的访…

神经网络常见激活函数 4-LeakyReLU函数

LeakyReLU LeakyReLU&#xff1a; Leaky Rectified Linear Unit 函数导函数 LeakyReLU函数 L e a k y R e L U { x x > 0 p x x < 0 p ∈ ( 0 , 1 ) \rm Leaky{ReLU} \left\{ \begin{array}{} x \quad x>0 \\ px \quad x<0 \end{array} \right. \quad p \in …