学习C++提供的线程库的原因
- Linux 提供的 pthread_create等线程相关函数无法在windows上使用, C++提供的线程相关函数可以跨平台使用
- C++使用了面向对象的思想进行了封装,相关线程方法更容易使用 。
线程相关的类
// 调用常用方法的类
// thread对象、mutex对象均不允许拷贝,但允许移动赋值/构造。
std::thread
std::mutex
std::condition_variable
线程初始化
线程初始化 :
// 线程初始
// 使用函数指针初始化线程
// threadFunction 为启动的线程函数
// x1, x2 为更具threadFunction形参传入的参数,如果threadFunction没参数就不传入
std::thread t1(threadFunction, x1, x2);
线程批量初始化:
方案一:
const int numThreads = 5;
std::thread threads[numThreads]; // 创建多个线程对象
// 启动多个线程
for (int i = 0; i < numThreads; ++i)
{ // 启动线程,执行 threadFunction(i) // 一定为移动赋值
threads[i] = std::thread(threadFunction, i);
}
// 等待所有线程执行完毕
for (int i = 0; i < numThreads; ++i)
{
// 线程回收
threads[i].join();
}
方案二
vector<std::thread> treadPool//创建
for (int i = 0; i < threadPool.size(); ++i)
{
// 一定为移动赋值 //启动线程
thradPool[i] = std::thread(threadFunction, i);
}
// 等待所有线程执行完毕
for (int i = 0; i < numThreads; ++i)
{
threads[i].join();
}
线程获取自身线程ID
#include <iostream>
#include <thread>
void threadFunction()
{
// 注意std::thread::id为线程库中的类型
std::thread::id this_id = std::this_thread::get_id();
std::cout << "Thread ID: " << this_id << std::endl;
}
int main()
{
std::thread t(threadFunction);
t.join();
return 0;
}
线程让出自身时间片
void threadFunction()
{
for (int i = 0; i < 5; ++i)
{
std::cout << "Thread A executing..." << std::endl;
std::this_thread::yield(); // 让出当前线程的执行
}
}
int main()
{
std::thread t(threadFunction);
for (int i = 0; i < 5; ++i)
{
std::cout << "Main thread executing..." << std::endl;
std::this_thread::yield(); // 让出当前线程的执行
}
t.join();
return 0;
}
互斥锁的基本使用
cpp
#include <iostream>
#include <thread>
#include <mutex>
// 创建一个互斥锁对象
std::mutex mtx;
void threadFunction(){
// 在需要保护共享资源的代码块前后分别加锁和解锁
mtx.lock();
std::cout << "Thread A executing..." << std::endl;
mtx.unlock();
}
int main()
{
std::thread t(threadFunction);
// 在需要保护共享资源的代码块前后分别加锁和解锁
mtx.lock();
std::cout << "Main thread executing..." << std::endl;
mtx.unlock();
t.join();
return 0;
}
条件变量的基本使用
wait 方法是 std::condition_variable 类的一个成员函数,用于使当前线程等待条件变量满足某个特定条件。通常与 std::unique_lock< std::mutex >结合使用(不能用std::lock_guard,因为其无法加锁、解锁接口,而条件变量需要加锁和解锁),用法如下:
std::condition_variable cv;
std::mutex mtx;
void some_function()
{
std::unique_lock<std::mutex> lock(mtx);
// 做一些工作...
cv.wait(lock); // 当前线程等待条件变量满足某个特定条件
// 继续执行...
}
在这个例子中,cv.wait(lock) 的调用使得当前线程进入等待状态,直到其他线程调用 cv.notify_one() 或 cv.notify_all() 来通知条件变量满足了某个特定的条件。被唤醒的线程会重新尝试获取互斥锁 lock,并检查条件是否满足,如果不满足,则继续等待。
需要注意的是,在调用 cv.wait(lock) 之前,必须先获取 lock 对应的互斥锁,这是因为 wait 方法在等待期间会释放互斥锁,以允许其他线程获得锁并对条件进行修改。当条件满足时,wait 方法会重新获取互斥锁并继续执行。
在 wait 方法中,可以传递一个额外的参数,用于指定等待期间的条件,例如:
cv.wait(lock, [](){ return some_condition; });
这样,当 some_condition 不满足时,当前线程会等待,直到其他线程修改了条件并通过 notify 或 notify_all 通知了条件的变化。
#include <iostream>
#include <thread>
// 条件变量是通过锁来实现的
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void threadFunction()
{
std::unique_lock<std::mutex> lock(mtx);
// 等待条件满足
cv.wait(lock, []{ return ready; });
std::cout << "Thread A executing..." << std::endl;
}
int main()
{
std::thread t(threadFunction);
{
// 出作用域自动解锁
std::lock_guard<std::mutex> lock(mtx);
// 设置条件为true
ready = true;
}
// read已经被修改为true 通知等待的线程可以开始执行
cv.notify_one();
t.join();
return 0;
}