在C#的多线程编程中,Monitor 是一种用于同步多个线程访问共享资源的机制。它是基于对象的锁定机制,能够有效地控制对代码块的访问,防止数据的不一致,其实与lock基本一样的。本文将详细介绍 Monitor 的特点、用法,并提供多个示例以展示其应用。
Monitor 的特点Monitor 通过锁定对象,确保同一时刻只有一个线程可以访问被锁定的代码块。Mutex,Monitor 的性能开销较小,适合在同一进程中的多线程环境中使用。Monitor 允许线程在等待某个条件时释放锁,这样其他线程可以获得锁,避免资源的浪费。Monitor 提供了较为简单的 APIs,如 Enter、Exit、Wait、Pulse 和 PulseAll。Monitor 的基本语法以下是 Monitor 的基本用法示例:
C#object lockObject = new object();
Monitor.Enter(lockObject); // 请求锁
try {
// ... 访问共享资源
} finally {
Monitor.Exit(lockObject); // 释放锁
}
Monitor 实现线程安全的计数器以下示例展示了如何使用 Monitor 来实现一个线程安全的计数器,确保只有一个线程可以对计数器进行更新。
C#namespace AppMonitor01
{
internal class Program
{
private static int counter = 0; // 共享资源
private static object lockObject = new object(); // 用于锁定代码块
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++)
{
Monitor.Enter(lockObject); // 请求锁
try
{
counter++; // 增加计数
}
finally
{
Monitor.Exit(lockObject); // 确保释放锁
}
}
}
}
}

在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);
}
}
}
