C++ 多线程编程和线程池

c++ 多线程需要包含thread头文件

cpp 复制代码
#include <thread>std::thread t(function_name, args...);

多线程调用函数代码如下

cpp 复制代码
#include <iostream>
#include <thread>
void print_message() 
{    
	std::cout << "Hello, world!" << std::endl;
}
int main() 
{    
	 std::thread t(print_message);    
	 t.join();
	     
	 return 0;
}

子线程和主线程同时执行,当子线程没执行完,主线程结束时,程序就会报错

join,主线程等待子线程执行完成后再执行,只能使用一次

detach,主程序结束,子线程会在后台执行

joinable,判断线程是否可以调用join和detach

cpp 复制代码
//当子线程没有执行完时,主线程会阻塞在join()位置
bool isJoin = thread.joinable()
if(isJoin)
{
	thread.join()// 让主线程等待子线程
}

note:

1、右值传递给左值引用会报错可以使用std::ref ,右值引用

2、多线程中传递的指针可能存在被释放的问题需要注意

3、线程安全,多线程的运行程序和单线程的运行结果都是一样的

实现线程安全可以使用互斥锁、信号量、条件变量等操作

cpp 复制代码
//互斥锁
std::mutex mtx;
mtx.lock();
//...
mtx.unlock();

lock_gurad,只在局部作用域中使用,不能复制和移动,轻量级锁

unqiue_lock,重量级锁,可以手动加锁、延迟加锁

手写实现一个线程池

cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <queue>
#include <vector>
#include <functional>
#include <condition_variable>

class ThreadPool {
public:
	ThreadPool(int numTread) : stop(false)
	{
		for (int i = 0; i < numTread; i++)
		{
			threads.emplace_back([this]
			{
				while (1)
				{
					std::unique_lock<std::mutex> lock(mtx);
					condition.wait(lock, [this]
						{
							return !tasks.empty() || stop;
						});
					if (stop && tasks.empty())
					{
						return;
					}

					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();
		for (auto& t : threads)
		{
			t.join();
		}
	}

	template<class F,class ... Args>
	void enqueue(F&& f, Args&& ... args)
	{
		std::function<void()> task =
			std::bind(std::forward<F>(f), std::forward<Args>(args)...);
		{
			std::unique_lock<std::mutex> lock(mtx);
			tasks.emplace(std::move(task));
		}
		condition.notify_one();
	}
private:
	bool stop;
	std::condition_variable condition;
	std::mutex mtx;
	std::vector < std::thread > threads;

	std::queue < std::function<void()>> tasks;
};
int main()
{
	// 创建一个线程池,里面包含4个线程
	ThreadPool pool(4);

	// 4个线程执行10个任务
	for (int i = 0; i < 10; i++)
	{
		// 往线程池里加任务
		pool.enqueue([i]()
			{
				std::cout << "task : " << i << " is runing " << std::endl;
				std::this_thread::sleep_for(std::chrono::seconds(1));
				std::cout << "task : " << i << " is done " << std::endl;
			}
		);
	}
	return 0;
}

参考资料

1、http://www.seestudy.cn/?list_9/31.html

相关推荐
cch891823 分钟前
易语言与C++:编程语言终极对决
开发语言·c++
HABuo26 分钟前
【linux线程(三)】生产者消费者模型(条件变量阻塞队列版本、信号量环形队列版本)详细剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
小肝一下1 小时前
每日两道力扣,day2
c++·算法·leetcode·职场和发展
CheerWWW3 小时前
C++学习笔记——this关键字、对象生命周期(栈作用域)、智能指针、复制与拷贝构造函数
c++·笔记·学习
lucky九年3 小时前
GO语言模拟C++封装,继承,多态
开发语言·c++·golang
漫随流水4 小时前
c++编程:D进制的A+B(1022-PAT乙级)
数据结构·c++·算法
tankeven4 小时前
HJ159 没挡住洪水
c++·算法
charlie1145141914 小时前
嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(5):调试进阶篇 —— 从 printf 到完整 GDB 调试环境
linux·c++·单片机·学习·嵌入式·c
paeamecium4 小时前
【PAT】 - Course List for Student (25)
数据结构·c++·算法·pat考试
小黄人软件4 小时前
MFC为什么不报空指针异常 2宏定义不改源码 用替换 用Log函数替换printf等 #define printf Log 优化版底层类Log显示
c++·mfc