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_lock unique(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

posted @ 2024-02-08 23:36  trashwin  阅读(5)  评论(0编辑  收藏  举报