云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

讲解C#中的信号量和屏障,以及它们在多线程编程中的应?场景

jxf315 2024-12-26 14:09:10 教程文章 27 ℃

在 C# 中,信号量(Semaphore)屏障(Barrier) 是多线程编程中常用的同步机制,它们用于解决不同的线程协调和同步问题。下面我将详细讲解它们的概念、用法以及实际应用场景。


1. 信号量(Semaphore)

1.1 概念

信号量 是一种用于控制 多个线程对共享资源的访问 的同步机制。它维护一个计数器,表示可以访问共享资源的线程数量:

  • 当线程请求访问时,信号量的计数器减 1。
  • 当线程释放资源时,信号量的计数器加 1。

信号量有两种类型:

  • Semaphore:允许多个线程访问共享资源(计数信号量)。
  • SemaphoreSlim:轻量级的信号量,适用于大多数情况下的并发编程。

1.2 使用 Semaphore 的示例

场景: 有 3 个资源,但 5 个线程要访问这些资源,每次最多只能允许 3 个线程访问资源。

using System;
using System.Threading;

class Program
{
    // 初始化信号量,最多允许 3 个线程访问资源
    static Semaphore semaphore = new Semaphore(3, 3);

    static void Main()
    {
        for (int i = 1; i <= 5; i++)
        {
            Thread thread = new Thread(AccessResource);
            thread.Name = #34;Thread {i}";
            thread.Start();
        }
    }

    static void AccessResource()
    {
        Console.WriteLine(#34;{Thread.CurrentThread.Name} is waiting to enter...");

        // 请求信号量(等待资源)
        semaphore.WaitOne();

        Console.WriteLine(#34;{Thread.CurrentThread.Name} has entered the critical section.");

        // 模拟线程占用资源的时间
        Thread.Sleep(2000);

        Console.WriteLine(#34;{Thread.CurrentThread.Name} is leaving the critical section.");

        // 释放信号量
        semaphore.Release();
    }
}

输出示例

Thread 1 is waiting to enter...
Thread 2 is waiting to enter...
Thread 3 is waiting to enter...
Thread 1 has entered the critical section.
Thread 2 has entered the critical section.
Thread 3 has entered the critical section.
Thread 4 is waiting to enter...
Thread 5 is waiting to enter...
Thread 1 is leaving the critical section.
Thread 4 has entered the critical section.
Thread 2 is leaving the critical section.
Thread 5 has entered the critical section.

1.3 信号量的应用场景

  • 资源访问控制:限制多个线程对共享资源的同时访问数量。
  • 连接池管理:如数据库连接池或网络连接池的管理。
  • 限流控制:在高并发应用中限制同时执行的任务数量。

2. 屏障(Barrier)

2.1 概念

屏障(Barrier) 是一种用于 协调多个线程阶段性执行 的同步机制。所有线程必须在屏障点等待,直到所有线程都到达该点,才能继续执行下一阶段。

核心特点:

  • 线程到达屏障点后会等待。
  • 当所有参与线程都到达屏障点时,屏障解除,所有线程继续执行。
  • 可以设置一个操作,在每次屏障点解除时执行(例如日志记录、进度更新等)。

2.2 使用 Barrier 的示例

场景: 4 个线程,每个线程需要分阶段完成任务,所有线程在每个阶段完成后,才能进入下一阶段。

using System;
using System.Threading;

class Program
{
    static Barrier barrier = new Barrier(4, (b) =>
    {
        Console.WriteLine(#34;All threads reached the barrier. Phase {b.CurrentPhaseNumber} completed.\n");
    });

    static void Main()
    {
        for (int i = 1; i <= 4; i++)
        {
            Thread thread = new Thread(DoWork);
            thread.Name = #34;Thread {i}";
            thread.Start();
        }
    }

    static void DoWork()
    {
        for (int phase = 0; phase < 3; phase++) // 模拟三阶段任务
        {
            Console.WriteLine(#34;{Thread.CurrentThread.Name} is working on Phase {phase}.");
            Thread.Sleep(new Random().Next(1000, 2000)); // 模拟工作时间

            // 到达屏障点并等待其他线程
            barrier.SignalAndWait();

            Console.WriteLine(#34;{Thread.CurrentThread.Name} passed the barrier for Phase {phase}.");
        }
    }
}

输出示例

Thread 1 is working on Phase 0.
Thread 2 is working on Phase 0.
Thread 3 is working on Phase 0.
Thread 4 is working on Phase 0.
All threads reached the barrier. Phase 0 completed.

Thread 1 passed the barrier for Phase 0.
Thread 2 passed the barrier for Phase 0.
Thread 3 passed the barrier for Phase 0.
Thread 4 passed the barrier for Phase 0.
Thread 1 is working on Phase 1.
Thread 2 is working on Phase 1.
...

2.3 屏障的应用场景

  • 多线程分阶段执行任务:需要确保每个阶段的任务都完成后,再进入下一阶段。
  • 并行算法的同步:如分布式计算中,多个节点完成一部分计算后进行结果汇总。
  • 阶段性同步:如多人协作项目,每个阶段的工作完成后再进入下一阶段。

3. 信号量与屏障的区别

特性

信号量(Semaphore)

屏障(Barrier)

作用

控制多个线程对共享资源的并发访问数量

使多个线程在某个阶段同步等待

控制机制

计数器(线程申请资源时计数减 1,释放时加 1)

所有线程必须到达屏障点才能继续执行

线程等待时机

等待资源的可用性

等待所有线程到达屏障点

应用场景

资源访问控制、限流控制

分阶段任务、并行算法同步


4. 总结

  • 信号量(Semaphore) 适用于控制多个线程对共享资源的访问,尤其在 资源池限流控制 的场景下使用。
  • 屏障(Barrier) 适用于需要 阶段性同步 的场景,保证所有线程在完成某一阶段任务后,再同步进入下一阶段。

通过合理选择信号量和屏障,可以有效地解决多线程编程中的线程同步问题,提高程序的执行效率和稳定性。

最近发表
标签列表