在C#的多线程编程中,Mutex 是一种用于同步多个线程的机制。它不仅适用于进程间的线程同步,还可以在同一进程内用于保护共享资源。本文将详细介绍 Mutex 的特点、用法,并提供多个示例以示范其应用。
Mutex 的特点Mutex 允许在不同进程之间进行同步,这使得它在处理需要进程间通信的场景时相当有用。Mutex,其他线程必须等待,直到该线程释放 Mutex。Mutex 允许设置超时。如果线程在指定时间内无法获得锁,可以选择放弃。Mutex 提供了清晰的接口,易于程序员使用。Mutex 的基本语法以下是 Mutex 的基本用法示例:
C#Mutex mutex = new Mutex();
mutex.WaitOne(); //请求锁
// ... 访问共享资源
mutex.ReleaseMutex(); //释放锁
Mutex 实现线程安全的计数器以下示例展示了如何使用 Mutex 来实现一个线程安全的计数器,确保只有一个线程可以对计数器进行更新。
C#using System;
using System.Threading;
class Program {
private static int counter = 0; // 共享资源
private static Mutex mutex = new Mutex(); // 创建 Mutex 实例
static void Main(string[] args) {
Thread[] threads = new Thread[5];
for (int i = 0; i < threads.Length; i++) {
threads[i] = new Thread(IncrementCounter);
threads[i].Start();
}
foreach (var thread in threads) {
thread.Join();
}
Console.WriteLine($"最终计数器的值: {counter}");
}
static void IncrementCounter() {
for (int i = 0; i < 1000; i++) {
mutex.WaitOne(); // 请求锁
try {
counter++; // 增加计数
} finally {
mutex.ReleaseMutex(); // 确保释放锁
}
}
}
}

随着 .NET 6 的发布,LINQ 中新增了两个便捷的扩展方法:
它们能根据指定的键(keySelector)从集合中一次性取得最小值或最大值所在的整个对象(而不仅仅是数值)。拥有这两个方法后,我们无需再手工使用 OrderBy() + First() 或者 OrderByDescending() + First() 的组合来取极值对象,代码变得更加简洁,也能避免没必要的排序操作,效率更高。
在开始动手实验之前,我们先定义一个简单的 Student 记录类型,并创建一个学生列表,包含学生的姓名和分数等信息。示例如下:
C#namespace AppMin
{
public record Student(string Name, int Marks);
internal class Program
{
static void Main(string[] args)
{
// 创建学生列表
var students = new List<Student>
{
new Student("张三", 520),
new Student("李四", 480),
new Student("王五", 550),
new Student("张飞", 430),
new Student("关羽", 550)
};
// 打印数据,确保数据已经正确初始化
foreach (var student in students)
{
Console.WriteLine($"{student.Name} - {student.Marks}");
}
}
}
}
在嵌入式系统、物联网(IoT)和工业通讯领域,串口通讯仍然是一种广泛使用的通信方式。本文将深入探讨如何使用C#实现一个健壮、高效的异步串口通讯管理器。
异步编程是现代.NET应用程序的重要特性,它允许:
我们的串口管理器将具备以下特性:
C#public class SerialPortManager : IDisposable
{
private SerialPort _serialPort;
private readonly string _portName;
private readonly int _baudRate;
private CancellationTokenSource _cancellationTokenSource;
// 数据接收事件
public event EventHandler<byte[]> DataReceived;
public SerialPortManager(string portName, int baudRate)
{
_portName = portName;
_baudRate = baudRate;
_cancellationTokenSource = new CancellationTokenSource();
}
}
在 C# 的 LINQ 查询中,Select 与 SelectMany 经常使用来处理集合或可查询对象。两者有些相似之处,但也有明显区别:
Select:将集合中的每个元素映射(投影)到一个新的形式,最终返回与原集合长度相同的序列。
SelectMany:针对集合中的每个元素返回一个可枚举序列,然后将所有子序列“压平”(Flatten)为一个新的序列。
以下例子演示如何使用 Select 将字符串列表中的每个元素转换成大写形式:
C#public class Program
{
public static void Main()
{
var fruits = new List<string> { "apple", "banana", "cherry" };
// 使用 Select 把每个字符串都转换为大写
var upperFruits = fruits.Select(fruit => fruit.ToUpper());
foreach (var item in upperFruits)
{
Console.WriteLine(item);
}
}
}

在C#的多线程编程中,lock 是一种非常常用的同步机制,用于保护共享资源,防止多个线程同时访问造成的数据不一致。本文将详细介绍 lock 的特点、用法,以及相关的示例。
lock 的特点lock 关键字块内,只允许一个线程进入,其他线程会被阻塞,直到当前线程释放锁。lock 通过申请对象的互斥锁(monitor)来防止其他线程进入同一代码块,可以有效避免由于多个线程同时访问共享资源而导致的死锁情况。lock 关键字语法简单,使得多线程同步的编码过程更加清晰,降低了错误的可能性。Mutex、Semaphore)相比,lock (其实是 Monitor 的一种语法糖)在执行上更为轻量,适合于保护简单的共享数据。lock 的基本语法lock 的基本语法如下:
C#lock (object lockObject) {
// 需要保护的代码块
}
lockObject 是一个用于同步的对象,通常是一个私有的对象,以防其他代码也使用它。
lock 进行线程安全的计数器