thread
std::thread
thread() noexcept
创建一个空线程对象,什么也不做
template <class Fn, class… Args>
explicit thread(Fn&& fn, Args&&… args)
创建线程,以 fn(args…) 作为线程函数执行
Fn 必须是可调用对象,可以是函数指针、函数对象、lambda 表达式、bind 表达式等
void countnumber(int id, unsigned int n) {
for (unsigned int i = 1; i <= n; i++);
cout << "Thread " << id << " finished!" << endl;
}
int main() {
thread th[10];
for (int i = 0; i < 10; i++)
th[i] = thread(countnumber, i, 100000000);
for (int i = 0; i < 10; i++)
th[i].join();
return 0;
}
传引用问题,由于线程的输入参数都为右值,所以如果要传引用,需要使用 std::ref() 包装为按引用的传递。
template<class T> void changevalue(T &x, T val) {
x = val;
}
int main() {
thread th[100];
int nums[100];
for (int i = 0; i < 100; i++)
th[i] = thread(changevalue<int>, ref(nums[i]), i+1);
for (int i = 0; i < 100; i++) {
th[i].join();
cout << nums[i] << endl;
}
return 0;
}
std::mutex
基本的互斥量,用于保护共享数据,防止多个线程同时访问
api
lock() // 加锁
unlock() // 解锁
try_lock() // 尝试加锁,如果已经被锁定,则返回 false,否则返回 true; 可以看成是 lock 的非阻塞版本
std::lock_guard
利用 RAII 机制,保证在定义时加锁(构造函数),作用域结束时(析构函数)自动调用 unlock() 解锁。不可移动不可复制。
常用写法
lock_guard
guard(mt);
std::unique_lock
lock_guard的粒度太大,只能在定义时加锁,作用域结束时解锁,如果想在作用域内的某个时间段加锁,某个时间段解锁,就需要使用 unique_lock(有时也用lock_guard,但是人为添加作用域)。可移动不可复制。
unique_lock
unique(mt); //默认上锁
unique_lockunique(mt, defer_lock); //不上锁
unique_lock可以在构造时加锁,后续可以使用unlock()解锁,再使用lock()加锁。
析构时会根据情况自动解锁,如果在构造时没有加锁,则析构时不会解锁。内部维护了一个状态值记录是否加锁。
std::atomic
将对数据的操作原子化,即不可分割,不会被其他线程打断;进而不用加锁,提高效率。
使用时可以直接当做普通变量使用。
#define MAX 100000
atomic<int> count = 0;
void countn(){
for(int i = 0; i < MAX; i++){
count++;
}
}
int main(){
thread t1(countn);
thread t2(countn);
t1.join();
t2.join();
cout << count << endl;
return 0;
}
std::condition_variable
条件变量,用于线程间的同步。
wait(unique_lock
& lock) // 等待,会自动解锁,等待唤醒后再加锁
wait(lock, pred) // 等待,直到pred返回true,相当于while(!pred) wait(lock);
wait_for(lock, rel_time) // 收到通知或者超时后返回
wait_for(lock, rel_time, pred) // 收到通知或者超时后返回,直到pred返回true
wait_until(lock, abs_time) // 收到通知或者超时后返回,和wait_for类似,区别在于使用绝对时间
wait_until(lock, abs_time, pred)
notify_one() // 唤醒一个等待的线程
notify_all() // 唤醒所有等待的线程
mutex mt;
condition_variable cv;
bool ready = false;
void print_id(int id){
unique_lock<mutex> lock(mt);
while(!ready){
cv.wait(lock);
}
cout << "Thread " << id << " finished!" << endl;
}
void go(){
unique_lock<mutex> lock(mt);
ready = true;
cout << "go!" << endl;
cv.notify_all();
}
int main(){
thread th[10];
for(int i = 0; i < 10; i++){
th[i] = thread(print_id, i);
}
cout << "10 threads ready" << endl;
go();
for(int i = 0; i < 10; i++){
th[i].join();
}
return 0;
}
condition_variable_any 是一个通用的条件变量,可以和任意的互斥量一起使用,而不需要是unique_lock
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律