当前位置: 首页 > news >正文

2017年免费建网站哪里有零基础网站建设教学培训

2017年免费建网站,哪里有零基础网站建设教学培训,天津设计公司联系方式,低代码无代码平台&#x1f9fe; 线程池八股文一、基础语法 & STLQ1&#xff1a;std::function<void()> task; 在这里是什么意思&#xff1f;在 workers_ 的线程循环里&#xff0c;定义了一个 task 变量&#xff0c;它是一个 通用可调用对象包装器。这里统一把所有提交的任务&#xff…


🧾 线程池八股文


一、基础语法 & STL

Q1:std::function<void()> task; 在这里是什么意思?

  • workers_ 的线程循环里,定义了一个 task 变量,它是一个 通用可调用对象包装器

  • 这里统一把所有提交的任务(lambda、函数等)存放到 tasks_ 队列中,工作线程取出来放到 task 里,再调用 task() 执行。


Q2:为什么要 std::move(tasks_.front())

  • 因为 tasks_ 是一个 std::queue<std::function<void()>>

  • tasks_.front() 返回的是引用,如果直接赋值会触发一次拷贝构造;

  • std::move 可以把任务对象的所有权转移到局部变量 task,避免额外拷贝,提高效率。

  • 注意:不能返回引用,因为 tasks_.pop() 后,front() 指向的元素生命周期就结束了。


Q3:workers_.emplace_back([this]{ ... }) 为什么用 emplace_back

  • workers_ 是一个 std::vector<std::thread>

  • emplace_back 可以在 vector 内部直接构造一个 std::thread 对象,避免一次多余的拷贝/移动。

  • 在这里,lambda 捕获了 this,所以每个线程都能访问 tasks_queue_mutex_condition_


Q4:为什么在 condition_.wait() 里必须用 unique_lock 而不是 lock_guard

  • condition_.wait() 内部会在阻塞期间 释放 queue_mutex_,唤醒后再重新加锁。

  • lock_guard 不能解锁再上锁,所以必须用 std::unique_lock<std::mutex>


二、并发编程原理

Q5:为什么 condition_.wait(lock, [this]{ return !tasks_.empty() || stop_; }); 要有谓词?

  • 因为可能发生 虚假唤醒 或竞争唤醒。

  • 如果不用谓词,线程可能在 tasks_ 仍然为空时就被唤醒,然后执行 task = tasks_.front() → 直接越界崩溃。

  • 谓词 !tasks_.empty() || stop_ 确保只有在队列里有任务,或者收到停止信号时,线程才会继续。


Q6:为什么在锁外执行 task()

task = std::move(tasks_.front());
tasks_.pop();
} // 这里锁释放
task(); // 在锁外执行
  • 因为 task() 可能是一个耗时任务,如果在持有 queue_mutex_ 时执行,就会阻塞其他线程从 tasks_ 取任务。

  • 正确做法:取出任务后立即释放 queue_mutex_,让其他线程也能并发消费队列。


Q7:析构函数里为什么要先 stop_ = truecondition_.notify_all()

  • 析构函数里加锁修改 stop_

    {std::unique_lock<std::mutex> lock(queue_mutex_);stop_ = true;
    }
    condition_.notify_all();
    
  • 必须先改 stop_,再通知所有等待在 condition_ 上的线程。

  • 否则线程被唤醒时看不到最新的 stop_ 值,会继续 wait,导致死锁。


Q8:为什么 stop_ 不需要是 std::atomic<bool>

  • 因为所有对 stop_ 的访问都在 queue_mutex_ 锁保护下。

  • 互斥锁已经保证了内存可见性和顺序一致性,所以没必要额外用 atomic


三、线程与任务模型

Q9:线程和 CPU 的关系是什么?

  • 在代码里,workers_ 存的是一组 std::thread 对象,每个线程需要被操作系统调度到 CPU 核心上才能运行。

  • 如果线程数 ≤ CPU 核心数 → 真并行;

  • 如果线程数 > CPU 核心数 → 操作系统用时间片轮转,让 workers_ 中的线程轮流在 CPU 上跑。


Q10:CPU 密集 vs IO 密集,在 ThreadPool 参数选择上有什么区别?

  • CPU 密集型任务:比如 task() 里做矩阵运算,CPU 总是满载,线程池大小 ≈ CPU 核心数。

  • IO 密集型任务:比如 task() 里做网络请求,CPU 大部分时间在等 IO → 可以设置 workers_ 数量为 CPU 核心数的 2~4 倍,提高 CPU 利用率。


四、扩展设计

Q11:现在的 submit(std::function<void()> task) 只能提交 void() 任务,如何支持返回值?

  • 可以改为用 std::packaged_task<T()> 封装任务,把 future 返回给调用者。

  • 工作线程依旧在 workers_ 中执行 (*task)();,结果会写入 future 的共享状态。


Q12:如果 task() 抛异常会怎样?

  • 如果 task() 里抛出未捕获的异常,该工作线程会调用 std::terminate(),导致整个程序崩溃。

  • 解决方法:在 task(); 外层包一层 try-catch,把异常捕获并记录下来,保证线程池不会因为一个任务挂掉。


五、面试总结套路(带参数名)

当面试官问你“解释一下这个线程池”时,你可以这样回答:

  1. 整体思路

    • workers_ 里预先创建了 N 个线程,它们在循环里等待任务。

    • 任务被压入 tasks_ 队列,condition_ 唤醒等待的线程。

    • 线程取任务时持有 queue_mutex_,保证对队列的访问安全。

    • 析构时设置 stop_ = true,通知所有线程退出并 join。

  2. 关键细节

    • std::function<void()> 存放任意任务。

    • std::unique_lock + condition_.wait() 防止虚假唤醒。

    • 任务取出后在锁外执行,避免阻塞其他线程。

    • 析构时先改 stop_notify_all(),避免死锁。

  3. 扩展点

    • 返回值支持 → std::packaged_task + std::future

    • 优先级任务 → std::priority_queue

    • 过载保护 → 限制 tasks_ 大小,丢弃或阻塞提交。

http://www.dtcms.com/a/425242.html

相关文章:

  • 诗敏家具网站是谁做的商标名称推荐
  • 百度提交网站入口网址海南网站建设多少钱
  • app加网站开发网站手机版跳转 seo
  • 怎么把网站排名排上去wordpress 批量加密
  • 宁夏建设厅网站免费搭建网站模板
  • 聊城做网站的公司价位查询房产信息个人的房产信息查询
  • 北京响应式网站设计怎么样优化关键词排名
  • 山西教育学会的网站建设设计制作散发寄递销售展示使用
  • 做百度网站排做类似淘宝的网站设计需要什么
  • 做导航网站有发展吗破解软件库合集资料网址大全
  • 站长查询站长工具天台县低价网站建设
  • 网站开发分为万网网站备案查询
  • 求个网站你懂我的意思吗wordpress 4.7优化精减
  • 做网站都需要什么步骤网站建设需要公司
  • 罗湖装修公司网站建设微盟是做什么的
  • 机器学习之优化器
  • 优秀的定制网站建设提供商化工企业常用推广网站
  • 饰品公司网站建设方案用凡科建设的网站安全吗
  • 查询域名的网站阿里云 wordpress 建站 教程
  • 网站侧边栏代码拼多多网站建设过程
  • 中工信融营销型网站建设大网站的二级域名
  • 网站建设工作会议上的讲话怎么建一个视频网站做推广
  • 淘宝网站边上的导航栏怎么做深圳梵高网站建设服务
  • 免费云建站企业邮箱收费吗
  • 百度做的网站免费建站排名
  • 现在外贸做哪个网站好国内好看的网页设计
  • 新开传奇网站发布网单免费自助建站代理
  • 大学院系网站建设18岁以上准备好纸巾免费网站
  • 导购网站如何做免费推广邢台123生活网
  • 查企业年报的网站徐州手机网站建设公司哪家好