C#线程同步的三类情景分析

C#线程同步的三类情景分析

在多线程的应用中,为了确保数据的正确性,我们需要对线程进行同步,避免多个线程同时对同一份数据进行修改。C#中提供了多种同步机制,其中包括线程同步的三类情景:Mutex、Monitor和AutoResetEvent。

Mutex

Mutex是由操作系统提供的同步原语,可以保证只有一个线程访问临界区。典型的使用方式如下:

using System.Threading;

Mutex mutex = new Mutex();

void Method1()
{
    mutex.WaitOne();
    try 
    {
        // 临界区代码
    }
    finally 
    {
        mutex.ReleaseMutex();
    }
}

void Method2()
{
    mutex.WaitOne();
    try 
    {
        // 临界区代码
    }
    finally 
    {
        mutex.ReleaseMutex();
    }
}

这里使用Mutex来保护两个方法中的临界区,确保它们不会被同时访问。当一个线程获得了Mutex的锁时,其他线程将会阻塞,直到拥有锁的线程释放它。

Monitor

Monitor是.NET Framework提供的同步机制,它可以保证在同一时间内只有一个线程访问临界区。典型的使用方式如下:

using System.Threading;

object lockObject = new object();

void Method1()
{
    lock(lockObject) 
    {
        // 临界区代码
    }
}

void Method2()
{
    lock(lockObject) 
    {
        // 临界区代码
    }
}

这里使用lock关键字来保证两个方法中的临界区不会同时被访问。当一个线程进入临界区时,其他线程将会阻塞,直到当前线程离开临界区。

AutoResetEvent

AutoResetEvent是一个基于事件的同步机制,它允许一个线程等待另一个线程的信号。典型的使用方式如下:

using System.Threading;

AutoResetEvent autoEvent = new AutoResetEvent(false);

void Method1()
{
    // 临界区代码
    autoEvent.Set();
}

void Method2()
{
    autoEvent.WaitOne();
    // 临界区代码
}

这里使用AutoResetEvent来等待Method1的信号,当Method1完成临界区操作后,调用autoEvent.Set()来通知正在等待的线程。Method2调用autoEvent.WaitOne()来等待信号的到来,从而保证临界区操作的同步性。

示例说明

下面是两个示例,演示了如何使用Mutex和Monitor来保护共享资源。

Mutex示例

using System.Threading;

class Counter
{
    private int count = 0;
    private Mutex mutex = new Mutex();

    public void Increment()
    {
        mutex.WaitOne();
        try 
        {
            count++;
        }
        finally 
        {
            mutex.ReleaseMutex();
        }
    }

    public void Decrement()
    {
        mutex.WaitOne();
        try 
        {
            count--;
        }
        finally 
        {
            mutex.ReleaseMutex();
        }
    }

    public int GetCount()
    {
        mutex.WaitOne();
        try 
        {
            return count;
        }
        finally 
        {
            mutex.ReleaseMutex();
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Counter c = new Counter();
        Thread t1 = new Thread(() => {
            for(int i = 0; i < 100000; i++) 
            {
                c.Increment();
            }
        });
        Thread t2 = new Thread(() => {
            for(int i = 0; i < 100000; i++) 
            {
                c.Decrement();
            }
        });
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();
        Console.WriteLine($"Count: {c.GetCount()}");
    }
}

这个示例演示了如何使用Mutex来保护一个计数器的临界区。Counter类有三个方法:Increment、Decrement和GetCount,这些方法分别执行对计数器的加、减和读操作。每个方法都获取Mutex的锁,并在临界区执行相应的操作。需要注意的是,在GetCount方法中也需要获取Mutex的锁,以保证读操作的安全性。

Monitor示例

using System.Threading;

class BankAccount
{
    private int balance = 0;

    public void Deposit(int amount)
    {
        lock(this) 
        {
            balance += amount;
        }
    }

    public void Withdraw(int amount)
    {
        lock(this) 
        {
            if(balance >= amount)
            {
                balance -= amount;
            }
            else 
            {
                throw new Exception("Insufficient funds");
            }
        }
    }

    public int GetBalance()
    {
        lock(this) 
        {
            return balance;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        BankAccount account = new BankAccount();
        Thread t1 = new Thread(() => {
            for(int i = 0; i < 100000; i++) 
            {
                account.Deposit(10);
            }
        });
        Thread t2 = new Thread(() => {
            for(int i = 0; i < 100000; i++) 
            {
                account.Withdraw(10);
            }
        });
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();
        Console.WriteLine($"Balance: {account.GetBalance()}");
    }
}

这个示例演示了如何使用Monitor来保护一个银行账户的临界区。BankAccount类有三个方法:Deposit、Withdraw和GetBalance,这些方法分别执行对账户余额的存、取和读操作。使用lock(this)来获取锁,确保每个方法执行时都只有一个线程能够访问临界区。需要注意的是,在Withdraw方法中,如果余额不足,则会抛出异常。同时,GetBalance方法也会获取锁,以保证读操作的安全性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#线程同步的三类情景分析 - Python技术站

(0)
上一篇 2023年6月6日
下一篇 2023年6月6日

相关文章

  • C#如何Task执行任务,等待任务完成

    当我们需要在应用程序中执行耗时的任务时,我们可以使用Task类。下面是使用Task执行任务并等待任务完成的攻略: 创建Task任务 要创建一个Task,我们可以使用Task.Run()方法来启动一个任务。该方法接受一个委托(Delegate)类型的参数,该委托指定要在新线程上运行的代码。 例如,下面是一个简单的Task创建示例: Task task = Ta…

    C# 2023年6月6日
    00
  • C#停止线程的方法

    C#中停止线程的方法主要有三种: 1. 使用Thread.Abort()方法 可以使用Thread.Abort()方法终止线程,但这是一种比较粗暴的方式,不太推荐使用,因为它可能会引发一些问题,例如无法释放线程所占用的资源、无法结束事务等。 示例代码: Thread thread = new Thread(new ThreadStart(DoWork)); …

    C# 2023年6月1日
    00
  • C#华氏温度和摄氏温度相互转换的方法

    下面是关于C#华氏温度和摄氏温度相互转换的方法的完整攻略。 一、思路 要实现华氏温度和摄氏温度相互转换,需要明确两者之间的计算公式,常用的公式如下: 摄氏度转华氏度公式:F = C x 1.8 + 32 华氏度转摄氏度公式:C = (F – 32) / 1.8 因此,无论是将摄氏度转换为华氏度,还是将华氏度转换为摄氏度,都可以依据上述公式来实现。在具体的实现…

    C# 2023年5月31日
    00
  • C#数组的常用操作方法小结

    以下是C#数组的常用操作方法小结的详细攻略: 数组概述 数组是一种存储相同类型数据的集合。在C#中,声明数组时需要指定数组的类型和长度。数组的下标从0开始,最大下标为长度减1。 int[] nums = new int[5]; // 声明一个长度为5的int类型数组 常用操作方法 1. 数组的遍历 遍历数组是一个常见的操作,可以使用C#的for循环遍历数组元…

    C# 2023年5月31日
    00
  • .net开发:为程式码加上行号的方法详解

    为程式码加上行号一般是在编写代码时为了方便阅读和调试而进行的。下面给出两种在.NET开发中为程序代码加上行号的方法详解。 方法一 步骤一:添加代码 在你想要添加行号的代码处新增以下代码: string[] lines = textBox1.Text.Split(‘\n’); for (int i = 0; i < lines.Length; i++) …

    C# 2023年5月31日
    00
  • C# IsDefined的问题

    C#中的IsDefined方法是用于确定一个枚举类型的指定名称是否已定义的方法。如果该枚举类型包含名称为指定名称的常数,则返回true,否则返回false。该方法的定义如下: public static bool IsDefined(Type enumType, object value); 其中,enumType是要检查的枚举类型,value是要检查的常数…

    C# 2023年6月7日
    00
  • C#中的静态成员、静态方法、静态类介绍

    C#中的静态成员、静态方法、静态类是面向对象编程中常见的概念,具有重要的实用价值和理论意义。下面,就这些概念进行详细的讲解。 静态成员 静态成员是指在一个类中,使用static关键字修饰的成员。这种类型的成员是不需要实例化对象就可以访问的,因为它们是属于整个类的,而不是属于某个对象的。静态成员可以包括静态变量和静态方法两种类型。 静态变量 静态变量(也叫静态…

    C# 2023年5月31日
    00
  • c# 使用谷歌身份验证GoogleAuthenticator的示例

    当需要进行双因素身份验证时,Google身份验证器是一种非常流行的选择。C#可以使用GoogleAuthenticator库来实现Google身份验证器。下面是使用GoogleAuthenticator的示例攻略: 步骤一:安装GoogleAuthenticator库 安装GoogleAuthenticator库的推荐方法是通过NuGet包安装。可以通过以下…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部