多线程随机数生成器程序异常排查与修复求助
双线程随机数生成与显示程序的问题分析及修复
问题描述
需要实现两个线程:
- 第一个线程每秒生成5个随机数,持续一分钟(共300个)
- 第二个线程每秒显示一个已生成的随机数
现有代码运行后不符合预期,控制台批量输出数字,后续是main函数循环的重复结果。
核心错误点
- 线程无同步机制:两个线程直接操作全局计数器和数组,存在竞态条件,第二个线程可能读取未生成的数据,输出逻辑混乱。
- 随机数种子重复初始化:在
firstThread的循环内反复调用srand(firstThreadCounter),每次生成随机数前重置种子,导致随机数不随机甚至重复。 - 输出缓冲区未刷新:
cout默认是行缓冲,未手动刷新时会累积输出,导致批量打印;同时误用/t代替\t作为制表符。 - 循环变量重定义:
firstThread内外层循环都用i,内层循环会覆盖外层变量,导致外层循环无法正确执行60次;main函数的嵌套打印循环也存在同样问题。 - 第二个线程无等待逻辑:直接按固定间隔读取,不管第一个线程是否已经生成对应位置的随机数,可能读取到未初始化的垃圾值。
修复后的代码
#include <iostream> #include <thread> #include <cstdlib> #include <chrono> #include <mutex> #include <condition_variable> #define NUMBER_LIMIT 300 int arr[NUMBER_LIMIT]; static size_t produced = 0, consumed = 0; std::mutex mtx; std::condition_variable cv; bool finished = false; void producerThread() { // 只初始化一次随机数种子 srand(time(nullptr)); for (size_t i = 0; i < 60; i++) { for (size_t j = 0; j < 5; j++) { std::lock_guard<std::mutex> lock(mtx); arr[produced] = rand(); produced++; // 通知消费者有新数据 cv.notify_one(); std::this_thread::sleep_for(std::chrono::milliseconds(200)); } } // 生产完成后标记状态 std::lock_guard<std::mutex> lock(mtx); finished = true; cv.notify_one(); } void consumerThread() { while (true) { std::unique_lock<std::mutex> lock(mtx); // 等待有新数据或者生产完成 cv.wait(lock, []{ return produced > consumed || finished; }); if (finished && produced == consumed) break; // 生产完成且所有数据已消费,退出 if (produced > consumed) { std::cout << arr[consumed] << '\t'; std::cout.flush(); // 立即刷新输出缓冲区 consumed++; } lock.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } std::cout << std::endl; } int main() { std::thread producer(producerThread); std::thread consumer(consumerThread); producer.join(); consumer.join(); // 正确遍历并打印所有随机数 std::cout << "\n所有生成的随机数:\n"; for (size_t row = 0; row < 30; row++) { for (size_t col = 0; col < 10; col++) { size_t idx = row * 10 + col; if (idx >= NUMBER_LIMIT) break; std::cout << arr[idx] << '\t'; } std::cout << '\n'; } return 0; }
关键改动说明
- 线程同步:使用
std::mutex保护共享变量(produced、consumed、finished和数组),用std::condition_variable让消费者线程等待新数据生成,避免空读或读取未初始化数据。 - 随机数种子初始化:将
srand(time(nullptr))移到生产者线程开头,只初始化一次,保证随机数的随机性。 - 输出优化:修正制表符为
\t,每次输出后调用std::cout.flush(),确保输出实时显示。 - 循环变量修正:重命名内外层循环变量(如
i和j、row和col),避免变量覆盖导致的逻辑错误。 - 消费者逻辑优化:增加循环判断,直到生产完成且所有数据都被消费才退出,保证所有生成的随机数都能被正确输出。
内容的提问来源于stack exchange,提问作者Roma Zinkiv
相关产品推荐
相关产品推荐

