std::thread
std::thread是一个用于创建和管理线程的类。它可以让程序在多个并发执行的线程中执行不同的任务。下面是std::thread的一些常用用法介绍:
创建线程:
void myFunction(int arg1, double arg2) {// 线程执行的代码
}
std::thread t(myFunction, 42, 3.14);
启动线程:
t.join(); //等待线程执行完毕
使用join()函数等待线程t执行完毕。
t.detach(); //分离线程
使用detach()函数将线程t从当前线程中分离,使其独立执行。
lock
与std::thread配合使用的两个常用互斥量(mutex)封装类是std::lock_guard和std::unique_lock。它们提供了一种方便的方式来保护共享资源,避免数据竞争。
std::lock_guard
std::lock_guard:是一个简单的RAII(资源获取即初始化)封装类,用于自动化互斥量的加锁和解锁。当std::lock_guard对象的生命周期结束时,会自动释放互斥量。
std::mutex mtx;void myFunction() {std::lock_guard<std::mutex> lock(mtx);// 对共享资源进行操作
}
其特点有:
1.自动加锁和解锁:std::lock_guard的主要目的是在其生命周期内自动加锁互斥量,并在生命周期结束时自动解锁互斥量。这种自动化的机制可以确保无论线程的执行路径如何,互斥量都会被正确地释放,从而避免了忘记解锁的错误。
2.RAII原则:std::lock_guard是一个基于RAII(资源获取即初始化)的封装类。它利用构造函数在创建对象时加锁互斥量,在析构函数中自动解锁互斥量。这种设计模式使得使用std::lock_guard更加方便和安全,因为无论代码流程如何,都能保证互斥量的正确加锁和解锁。
3.作用域限定:std::lock_guard的生命周期受限于其定义的作用域。这意味着它只在其所在的作用域范围内有效,一旦超出该范围,std::lock_guard会自动析构并解锁互斥量。这样可以避免在不需要保护共享资源时持有互斥量的开销和潜在的死锁情况。
4.不可拷贝和移动:std::lock_guard不可拷贝和移动,这是因为它的构造函数是对互斥量进行加锁操作,析构函数是对互斥量进行解锁操作。如果std::lock_guard可以被拷贝或移动,那么在复制或移动时可能导致两个对象同时持有同一个互斥量,从而破坏互斥量的语义和可靠性。因此,std::lock_guard只能通过传值方式在函数调用中传递。
std::unique_lock
std::unique_lock:是一个更灵活的互斥量封装类,与std::lock_guard相比,它提供了更多的功能,如延迟加锁、条件变量的支持等。
std::mutex mtx;void myFunction() {std::unique_lock<std::mutex> lock(mtx);// 对共享资源进行操作
}
unique_lock还可以通过std::adopt_lock参数,接管已经加锁的互斥量,这对于需要多次加解锁的情况很有用。
std::mutex mtx;
mtx.lock();void myFunction() {std::unique_lock<std::mutex> lock(mtx, std::adopt_lock);// 对共享资源进行操作
}
其特点有:
1.延迟加锁和手动解锁:std::unique_lock允许在需要时延迟加锁互斥量,以及在需要时手动解锁互斥量。这使得可以根据需要对互斥量进行更细粒度的控制。例如,可以先锁定互斥量,但稍后再解锁,或者只在某些条件满足时才加锁。
2.条件变量支持:std::unique_lock提供了与条件变量(std::condition_variable)协同工作的支持。它可以在等待条件变量时自动释放互斥量,并在条件满足后重新获取互斥量。这样可以避免无效的忙等待,提高线程的效率。
3.灵活的构造和析构:std::unique_lock的构造函数可以接受一个互斥量对象和一些可选的参数,用于指定不同的锁定策略。例如,可以选择使用std::defer_lock参数来延迟加锁,或者使用std::adopt_lock参数来接管已经加锁的互斥量。同时,std::unique_lock的析构函数会自动解锁互斥量,确保互斥量在适当的时候被解锁。
4.可移动性:std::unique_lock是可移动的,可以通过std::move进行移动语义的操作。这使得可以方便地将std::unique_lock对象传递给其他函数或线程,而不需要进行额外的拷贝操作。
5.更大的灵活性:由于std::unique_lock提供了更多的功能和选项,因此它比std::lock_guard更灵活。它适用于更复杂的情况,如需要多次加解锁、需要等待条件变量或需要与其他线程进行交互等。