Cpp多线程

线程创建

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;
}
相关推荐
昵称小白17 小时前
复杂度分析方法
算法
科研前沿17 小时前
2026 数字孪生前沿科技:全景迭代报告 —— 镜像视界生成式孪生(Generative DT)技术白皮书
大数据·人工智能·科技·算法·音视频·空间计算
学涯乐码堂主19 小时前
有趣的“打擂台算法”
c++·算法·青少年编程·gesp
Tutankaaa20 小时前
知识竞赛题库设计全攻略
人工智能·算法
WolfGang00732120 小时前
代码随想录算法训练营 Day50 | 图论 part08
数据结构·算法·图论
aini_lovee1 天前
多目标粒子群优化(MOPSO)双适应度函数MATLAB实现
人工智能·算法·matlab
yong99901 天前
图像融合与拼接:完整MATLAB工具箱
算法·计算机视觉·matlab
春风不语5051 天前
深入理解主成分分析(PCA)
算法
apollowing1 天前
启发式算法WebApp实验室:从搜索策略到群体智能的能力进阶(二十二)
算法·启发式算法·web app