线程数量并不是越多越好,有些情况下,需要限制线程的数量。
这里需要用到互斥锁mutex,条件变量condition_variable,通用互斥锁包装器unique_lock
std::unique_lock也可以提供自动加锁、解锁功能,比std::lock_guard更加灵活。
类 unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。
unique_lock比lock_guard使用更加灵活,功能更加强大。
使用unique_lock需要付出更多的时间、性能成本。
全局的互斥锁m,用于锁定“process_number”,搭配unique_lock使用。
当一个线程执行完了之后就让process_number减1,然后唤醒所有等待线程
条件变量(condition variable),c++11中提供了#include <condition_variable>头文件,其中的std::condition_variable可以和std::mutex结合一起使用,其中有两个重要的接口,notify_one()和wait(),
wait()可以让当前线程陷入休眠状态。(也就是程序停止在wait处不再往下执行)
notify_all()就是唤醒处于wait中的所有线程(可能当时有很多线程都处于wait状态)。
————————————————
版权声明:本文为CSDN博主「yxpandjay」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
这里再condition.wait(lck)外面还要套一层循环while(process_number>5)的意思就是,因为同时唤醒了很多线程,
while (process_number > 5) {
condition.wait(lck);
}
如果没有这一层循环可能会有两个或者多个线程反应快同时启动,那就不可能限制住线程数量了,
因此需要在每个线程重启启动的时候,都去看看循环中的条件是否满足,再去执行,如果有其他线程抢先了,就继续wait
完整代码:
#include <iostream>
#include <thread>
#include <mutex>
#include <stdio.h>
#include<vector>
using namespace std;
mutex m;
condition_variable condition;
int process_number;
void t1(int id) {
if (process_number > 5) {
unique_lock<mutex> lck(m);
printf("id: %d, process_number: %d, waiting thread ID %d\n", id, process_number, std::this_thread::get_id());
while (process_number > 5) {
condition.wait(lck);
}
}
process_number += 1;
printf("id: %d, process_number: %d, doing thread ID %d\n", id, process_number, std::this_thread::get_id());
double sum = 0;
for (double i = 0; i < 1e10; i++) {
sum += i;
}
printf("id: %d, process_number: %d, doing thread ID %d get sum = %f\n", id, process_number, std::this_thread::get_id(),sum);
process_number -= 1;
condition.notify_all();
}
int main() {
process_number = 0;
vector<thread> th_set;
for (int i = 0; i < 20; i++) {
//thread th1(t1,i);
//th1.join();
th_set.push_back(thread(t1, i));
}
for (auto &th : th_set) {
th.join();
}
system("pause");
return 0;
}
一开始有6个线程开始工作,其他线程等待。
当id=3的线程执行结束了之后,id=9的线程开始执行。
这里要注意的是,再for循环中开启线程不可以这样写:
for (int i = 0; i < 20; i++) {
thread th1(t1,i);
th1.join();
}
因为join是子线程执行完后主线程回收子线程资源,本来没啥毛病,但是用在for循环中就会导致主线程在for循环里面等着线程执行完了回收资源,那就等于顺序执行,同一时间只执行一个线程(自行测试)
那么解决方法就是先用一个vector把线程先装起来,等for循环结束以后再统一回收资源。
vector<thread> th_set;
for(int i = 0; i < 20; i++) {
th_set.push_back(thread(t1, i));
}