线程创建
thread 线程名(函数名,参数)
cpp
#include<iostream>
#include<string>
#include<thread>
using namespace std;
#if 1
void printHello(string msg)
{
cout << msg << endl;
}
int main()
{
thread thread1(printHello, "Hello");//创建线程,thread 线程名(函数名,参数)
//thread1.join();//程序检查线程是否结束,若未结束,主线程会阻塞
//thread1.detach();//分离主线程与其他线程,主线程不会等
bool isJoin = thread1.joinable();//返回布尔值,判断线程能否被join等待
if (isJoin)
{
thread1.join();
}
return 0;
}
#endif
未定义错误
cpp
#include<iostream>
#include<thread>
#include<memory>
using namespace std;
//传递引用类型
#if 0
void foo(int& x)
{
x += 1;
}
int main()
{
int a = 1;
//thread t(foo, 1);//程序需要一个引用类型变量,但传了一个1临时变量(结束没分配空间)
thread t(foo, ref(a));//ref()将变量转换为他的引用类型
t.join();
cout << a << endl;
return 0;
}
#endif
//传递局部变量
#if 0
thread t;
void foo(int& x)
{
x += 1;
}
int test()
{
int a = 1;
t = thread(foo, ref(a));//传递局部变量,test结束时a被释放,foo中无法取a的引用
}
int main()
{
test();
t.join();
return 0;
}
#endif
//传递指针类型若指针被提前delete了也会产生未定义错误
//用智能指针管理内存泄漏
#if 0
class A {
public:
void foo()
{
cout << "Hello" << endl;
}
};
int main()
{
shared_ptr<A> a = make_shared<A>();
thread t(&A::foo, &a);
t.join();
return 0;
}
#endif
//使用友元函数访问私有成员函数
#if 0
class A {
private:
friend void thread_foo();
void foo()
{
cout << "Hello" << endl;
}
};
void thread_foo()
{
shared_ptr<A> a = make_shared<A>();
thread t(&A::foo, &a);
t.join();
}
int main()
{
thread_foo();
return 0;
}
#endif
互斥锁
cpp
#include<iostream>
#include<string>
#include<thread>
#include<mutex>
using namespace std;
/*
用互斥锁解决共享问题
防止多个线程同时操作同一个变量
*/
#if 0
int a = 0;
mutex mtx;//互斥锁
void func()
{
for (int i = 0; i < 10000; i++)
{
mtx.lock();//加锁
a += 1;
mtx.unlock();//解锁
}
}
int main()
{
thread t1(func);
thread t2(func);
t1.join();
t2.join();
cout << a << endl;
return 0;
}
#endif
死锁
cpp
#include<iostream>
#include<string>
#include<thread>
#include<mutex>
using namespace std;
#if 0
/*
死锁:互斥、请求与保持、不可剥夺、循环等待
打破上面四个条件之一就可以解决死锁问题
*/
mutex m1, m2;
void func1()
{
m1.lock();
m2.lock();
m1.unlock();
m2.unlock();
}
void func2()
{
m2.lock();
m1.lock();
m1.unlock();
m2.unlock();
}
int main()
{
thread t1(func1);
thread t2(func2);
t1.join();
t2.join();
return 0;
}
#endif
自动锁
cpp
#include<iostream>
#include<string>
#include<thread>
#include<mutex>
using namespace std;
/*
用来管理互斥锁(Mutex)的 RAII(资源获取即初始化) 模板类。
它们的主要作用是防止死锁:在构造时自动加锁
在作用域结束析构时自动解锁。
lock_guard
严格的生命周期:加锁和解锁完全依赖于代码块的作用域。
不可复制/不可移动:一旦创建,就不能转移锁的所有权。
不支持中途解锁:不能手动调用 unlock()。
unique_lock
支持手动控制:可以随时调用 lock() 和 unlock()。
支持延迟加锁:可以在构造时不立即加锁(传入 std::defer_lock)。
支持所有权转移:可以使用 std::move() 将锁转交给另一个 unique_lock 对象。
配合条件变量:使用 std::condition_variable 时必须配合 unique_lock。
*/
#if 0
mutex mtx;
int shared_data = 0;
void func()
{
for (int i = 0; i < 10000; i++)
{
// 构造时加锁,函数结束(作用域结束)自动解锁
lock_guard<mutex> lock(mtx);//用这个就不用自己写lock和unlock了
shared_data++;
}
}
int main()
{
thread t1(func);
t1.join();
return 0;
}
#endif
#if 0
int shared_data = 0;
timed_mutex mtx;
void func()
{
for (int i = 0; i < 10000; i++)
{
// 构造时加锁,函数结束(作用域结束)自动解锁
unique_lock<timed_mutex> lk(mtx,defer_lock);//defer_lock构造时还没有加锁,需要手动加锁,自动析构
//lock.lock();
lk.try_lock_for(std::chrono::seconds(5));//延迟一段时间加锁,要用timed_mutex类型的锁,若等待一段时间还没获取则直接返回
shared_data++;
}
}
int main()
{
thread t1(func);
t1.join();
return 0;
}
#endif
单例模式
cpp
/*
单例模式
全局唯一:一个类只能创建一个实例对象
如日志类
*/
#include<iostream>
#include<thread>
#include<mutex>
#include<string>
#if 0
static Log* log = nullptr;
static std::once_flag once;
class Log {
public:
Log() {};
//全局只有一个,禁用拷贝构造和=号
Log(const Log& log) = delete;
Log& operator = (const Log & log) = delete;
//用静态方法使用
static Log& GetInstance()//静态成员函数只能访问静态成员变量,因为在编译器就完成初始化
{
//static Log log;//饥汉模式,没有需求就创建好
//return log;
//懒汉模式--需要的时候再创建
std::call_once(once,init);
return *log;
}
void PrintLog(std::string msg)
{
std::cout << msg << std::endl;
}
static void init() {
if (!log)log = new Log;
}
};
void func()
{
Log::GetInstance().PrintLog("error");
}
int main()
{
//两个线程同时进入单例模式可能声明两次,要用call_once保证在多个线程中只执行一次,只能在线程中使用,不能在main函数中
std::thread t1(func);
std::thread t2(func);
t1.join();
t2.join();
return 0;
}
#endif
条件变量
cpp
/*
条件变量--需要跟互斥锁结合使用
生产者与消费者模型
生产者加任务/通知
消费者取任务/等待
*/
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>
#if 0
std::queue<int> g_queue;
std::condition_variable g_cv;
std::mutex mtx;
void Producer()
{
for (int i = 0; i < 10; i++)
{
std::unique_lock<std::mutex> lock(mtx);
g_queue.push(i);
//通知消费者取任务
g_cv.notify_one();
std::cout << "Producer" << i << std::endl;
}
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
void Consumer()
{
while (1)
{
std::unique_lock<std::mutex> lock(mtx);
//获得队列取任务,若任务为空则阻塞等待
g_cv.wait(lock, []() {return !g_queue.empty(); });
int value = g_queue.front();
g_queue.pop();
std::cout << "Consumer" <<value<< std::endl;
}
}
int main()
{
std::thread t1(Producer);
std::thread t2(Consumer);
t1.join();
t2.join();
return 0;
}
#endif
线程池
cpp
/*
线程池
提前维护一个线程数组和一个任务队列来完成其中的线程任务
提高效率
线程存在线程数组中
线程从任务队列中取任务
生产者向任务队列中加任务
构造函数中确定起始线程个数,每个线程在任务队列中取任务执行
给用户一个enqueue接口加任务
*/
#include<iostream>
#include<thread>
#include<mutex>
#include<string>
#include<queue>
#include<condition_variable>
#include<vector>
#include<functional>
using namespace std;
class ThreadPool {
public:
ThreadPool(int numThreads) :stop(false)
{//用户指定线程数量
for (int i = 0; i < numThreads; i++)
{
threads.emplace_back([this] {
//向线程池加线程
while (1)
{// 1. 上锁:保证操作队列时只有一个线程在访问
std::unique_lock<std::mutex>lock(mtx);
// 2. 条件等待:
// 等待条件满足:队列不为空 或 线程池要停止
// 等待期间会自动释放锁,被唤醒后重新加锁
condition.wait(lock, [this] {
return !tasks.empty() || stop;
});
// 3. 只要关闭标记为true,直接退出
if (stop) {
return;
}
// 4. 从队列头部取出一个任务
// std::move 提高效率,避免拷贝
std::function<void()>task(std::move(tasks.front()));
//将任务从队列中移除
tasks.pop();
lock.unlock();
task();
}
});
}
}
~ThreadPool() {
std::unique_lock<std::mutex>lock(mtx);
stop = true;
condition.notify_all();
lock.unlock();
// 等待所有线程执行完毕
for (auto& t : threads) {
t.join();
}
}
//在函数模板中加&&是万能引用
template<class F, class... Args>//可变参数模板 的语法,专门用来 "一次性接收任意多个参数"
void enqueue(F&& f, Args&&...args) {
//function<>函数包装器:统一各种可调用对象的类型,方便存队列、做回调、线程池任务管理(把需要传参才能调用的函数,变成 不需要传参、直接调用就能执行的任务。)
std::function<void()>task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);//bind函数适配器(函数名,参数列表)
{//分出锁的范围
std::unique_lock<std::mutex> lock(mtx);
tasks.emplace(std::move(task));
}
condition.notify_one();//唤醒一个被wait的线程
}
private:
std::vector<std::thread> threads;//线程数组
std::queue<std::function<void()>> tasks;//任务队列
std::mutex mtx;//互斥锁管理
std::condition_variable condition;//条件变量
bool stop;//中止
};
int main()
{
ThreadPool pool(4);
for (int i = 0; i < 10; i++)
{
pool.enqueue([i] {
std::cout << "task:" << i << " is running" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "task:" << i << " is done" << std::endl;
});
}
return 0;
}