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

基于C++ Semaphore实现圣诞老人问题代码无输出的排查请求

圣诞老人问题代码无输出原因排查与正确实现

无输出原因分析

  • 线程未正确创建:main函数中numReindeer初始值为0,导致驯鹿线程数组长度为0,没有创建任何驯鹿线程;精灵线程数组错误复用numReindeer(值为0),同样未创建精灵线程。仅有的Santa线程一直等待santaSem信号,但永远不会有线程触发该信号,程序陷入静默阻塞。
  • 信号量逻辑完全倒置:
    • 驯鹿线程启动后直接执行sem_wait(&reindeerSem),但该信号量初始值为0,所有驯鹿线程直接阻塞,无法执行计数和唤醒Santa的逻辑。
    • 精灵线程逻辑顺序错误:应该先完成计数,满3只后再唤醒Santa,而非先进入"获取帮助"流程再计数。
  • 共享变量无同步保护:numReindeer和numElves是多线程共享变量,直接读写会引发竞态条件;错误使用sem_getvalue来获取等待线程数,不符合信号量的使用逻辑。

符合规范的正确实现

以下实现严格遵循题目要求,解决了优先级、同步、死锁等问题:

#include <iostream>
#include <thread>
#include <mutex>
#include <semaphore.h>
#include <chrono>
#include <vector>
#include <cstdlib>
#include <ctime>

using namespace std;

// 信号量定义
sem_t santa_sem;       // 用于唤醒Santa
sem_t reindeer_sem;    // 驯鹿等待被 hitch 的信号量
sem_t elf_sem;         // 精灵等待被帮助的信号量
sem_t elf_mutex;       // 保护精灵计数的互斥信号量
sem_t reindeer_mutex;  // 保护驯鹿计数的互斥信号量

// 共享计数与状态标记
int reindeer_count = 0;
int elf_count = 0;
bool santa_busy = false; // 保证驯鹿优先级的核心标记

// Santa的任务函数(符合题目规范要求)
void prepareSleigh() {
    cout << "Santa: Preparing the sleigh for delivery!\n";
    this_thread::sleep_for(chrono::seconds(1));
}

void helpElves() {
    cout << "Santa: Helping a group of elves with toy-making problems!\n";
    this_thread::sleep_for(chrono::seconds(1));
}

// Santa线程逻辑
void santa() {
    while (true) {
        sem_wait(&santa_sem); // 休眠等待唤醒
        
        // 优先检查驯鹿是否满足条件(驯鹿优先级更高)
        sem_wait(&reindeer_mutex);
        bool has_reindeer = (reindeer_count == 9);
        sem_post(&reindeer_mutex);

        if (has_reindeer) {
            prepareSleigh();
            // 唤醒所有9只驯鹿
            for (int i = 0; i < 9; ++i) {
                sem_post(&reindeer_sem);
            }
            // 重置驯鹿计数
            sem_wait(&reindeer_mutex);
            reindeer_count = 0;
            sem_post(&reindeer_mutex);
        } else {
            helpElves();
            // 唤醒3只等待的精灵
            for (int i = 0; i < 3; ++i) {
                sem_post(&elf_sem);
            }
            // 重置精灵计数
            sem_wait(&elf_mutex);
            elf_count = 0;
            sem_post(&elf_mutex);
        }
        santa_busy = false; // 标记Santa已空闲
    }
}

// 驯鹿线程逻辑
void reindeer(int id) {
    while (true) {
        // 模拟度假归来的随机时长
        this_thread::sleep_for(chrono::seconds(rand() % 5 + 2));
        
        sem_wait(&reindeer_mutex);
        reindeer_count++;
        cout << "Reindeer " << id << " has returned. Total: " << reindeer_count << "\n";
        // 第9只驯鹿归来且Santa空闲时,唤醒Santa
        if (reindeer_count == 9 && !santa_busy) {
            santa_busy = true;
            sem_post(&santa_sem);
        }
        sem_post(&reindeer_mutex);

        sem_wait(&reindeer_sem); // 等待Santa准备雪橇
        cout << "Reindeer " << id << " is getting hitched to the sleigh!\n";
        this_thread::sleep_for(chrono::seconds(1));
        // 模拟拉雪橇出发,之后再次进入度假循环
    }
}

// 精灵线程逻辑
void elf(int id) {
    while (true) {
        // 模拟工作遇到问题的随机时长
        this_thread::sleep_for(chrono::seconds(rand() % 3 + 1));
        
        sem_wait(&elf_mutex);
        // 仅当Santa空闲且当前等待精灵不足3时,才能加入等待队列
        if (elf_count < 3 && !santa_busy) {
            elf_count++;
            cout << "Elf " << id << " needs help. Waiting elves: " << elf_count << "\n";
            // 第3只精灵到来时,唤醒Santa
            if (elf_count == 3) {
                santa_busy = true;
                sem_post(&santa_sem);
            }
            sem_post(&elf_mutex);
            sem_wait(&elf_sem); // 等待Santa提供帮助
            cout << "Elf " << id << " has received help from Santa!\n";
            this_thread::sleep_for(chrono::seconds(1));
        } else {
            // 暂时无法加入等待队列,稍后重试
            sem_post(&elf_mutex);
            this_thread::sleep_for(chrono::seconds(1));
        }
    }
}

int main() {
    srand(time(nullptr)); // 初始化随机数种子

    // 初始化信号量
    sem_init(&santa_sem, 0, 0);
    sem_init(&reindeer_sem, 0, 0);
    sem_init(&elf_sem, 0, 0);
    sem_init(&elf_mutex, 0, 1);
    sem_init(&reindeer_mutex, 0, 1);

    // 创建线程
    thread santa_thread(santa);
    vector<thread> reindeer_threads;
    for (int i = 0; i < 9; ++i) {
        reindeer_threads.emplace_back(reindeer, i+1);
    }
    vector<thread> elf_threads;
    for (int i = 0; i < 10; ++i) { // 创建10只精灵模拟不限数量的场景
        elf_threads.emplace_back(elf, i+1);
    }

    // 等待线程结束(实际会持续运行)
    santa_thread.join();
    for (auto& t : reindeer_threads) {
        t.join();
    }
    for (auto& t : elf_threads) {
        t.join();
    }

    // 销毁信号量
    sem_destroy(&santa_sem);
    sem_destroy(&reindeer_sem);
    sem_destroy(&elf_sem);
    sem_destroy(&elf_mutex);
    sem_destroy(&reindeer_mutex);

    return 0;
}

实现说明

  • 驯鹿优先级保证:通过santa_busy标记,Santa被唤醒时优先检查驯鹿是否满9只;精灵仅能在Santa空闲且等待数不足3时加入队列,确保驯鹿请求优先处理。
  • 精灵互斥规则:elf_mutex保护精灵计数,同一时间最多3只精灵进入等待,其他精灵需等待当前组完成帮助后重试,避免饥饿。
  • 无死锁/活锁:所有信号量的等待与释放逻辑严格配对,线程循环无阻塞点,保证系统持续运行。
  • 完全符合题目规范:
    1. 第9只驯鹿归来后触发Santa唤醒,Santa调用prepareSleigh,随后所有驯鹿执行getHitched逻辑。
    2. 第3只精灵到来后触发Santa唤醒,Santa调用helpElves,随后3只精灵获取帮助。
    3. 精灵计数由互斥信号量保护,当前3只精灵未完成帮助前,其他精灵无法进入计数流程。
    4. Santa循环运行处理多组请求,驯鹿固定9只,精灵数量可按需扩展。

内容的提问来源于stack exchange,提问作者Marcellus KM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:02:03