You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何同时使用ThreadPool与Semaphore实现递归递减打印功能?

使用ThreadPool和SemaphoreSlim实现递归递减打印

问题分析

你之前的ThreadPool版本代码出现终止值重复打印的问题,根源在于递归逻辑的执行时机和信号量控制不匹配,加上分支重复代码导致的逻辑冗余。原代码中,每次递归调用通过线程池异步执行,但信号量释放和递归入队的顺序可能触发多次终止条件,同时if分支的独立逻辑也容易引发重复执行。

修正后的实现方案

我们需要统一递归逻辑,用信号量正确保护控制台输出和递归流程,避免异步执行带来的参数捕获和并发问题。以下是修正后的完整代码:

核心思路

  1. 用SemaphoreSlim创建单许可信号量,保证同一时间只有一个线程进入打印和递归入队的临界区。
  2. 统一打印逻辑,减少分支重复代码,避免原代码中else分支打印count-1、if分支打印1的不一致问题。
  3. 提前捕获递归参数,避免异步闭包导致的参数值异常。

完整代码

// 静态单许可信号量,保证串行执行临界区代码
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

private static void RecursionWithThreadPool(int count)
{
    _semaphore.Wait();
    try
    {
        // 统一打印当前数值,避免分支逻辑差异
        Console.WriteLine("ThreadPool Current value is {0}", count);
        
        // 递归终止条件:count递减到1时停止
        if (count > 1)
        {
            // 提前赋值避免闭包捕获变化的count值
            int nextCount = count - 1;
            ThreadPool.QueueUserWorkItem(_ => RecursionWithThreadPool(nextCount));
        }
    }
    finally
    {
        // 确保信号量始终被释放,避免死锁
        _semaphore.Release();
    }
}

代码说明

  • 信号量控制:SemaphoreSlim(1,1)限制同一时间只有一个线程执行打印和递归入队操作,既保证控制台输出有序,也避免递归逻辑并发执行导致的混乱。
  • 统一逻辑:无论是否是终止条件,都直接打印当前count值,递归时传递count-1,彻底解决原代码中两次打印1的问题。
  • 闭包参数处理:提前将count-1赋值给nextCount,避免线程池异步执行时捕获到后续变化的count变量,确保递归参数准确。
  • finally释放:在finally块中释放信号量,无论代码是否抛出异常,都能保证信号量不会被永久占用。

调用示例

// 从5开始递归递减打印
RecursionWithThreadPool(5);
// 等待线程池任务执行完成(生产环境可使用CountdownEvent等更可靠的等待方式)
Thread.Sleep(1000);

输出结果:

ThreadPool Current value is 5
ThreadPool Current value is 4
ThreadPool Current value is 3
ThreadPool Current value is 2
ThreadPool Current value is 1

原代码错误原因回顾

你遇到的重复打印1的问题,本质是原代码逻辑的不一致:

  • 当count=2时,else分支打印count-1=1,同时入队count-1=1的递归调用;
  • 线程池执行该递归调用时,if分支又会打印一次1,最终导致两次输出。
    修正后的代码统一打印当前count值,递归传递count-1,从根源避免了重复打印。

内容的提问来源于stack exchange,提问作者Вася Пупкин

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:54:57