线程池 c++11

线程池 c++11

左值引用与右值引用 & 与 &&

在C++中,左值(Lvalues)和右值(Rvalues)是用于描述表达式和对象的两个基本概念。

  1. 左值(Lvalues):

    • 左值是指在内存中有确定位置的表达式或对象。它们可以出现在赋值语句的左边。
    • 左值可以被取地址,即可以使用取地址运算符&获取它们的地址。
    • 典型的左值包括变量、数组元素、类成员等。
    cppCopy codeint x = 10; // x是左值
    int arr[5]; // arr是左值
    
  2. 右值(Rvalues):

    • 右值是指在内存中没有确定位置的临时表达式或对象。它们通常出现在赋值语句的右边。
    • 右值不能被直接取地址,即不能使用取地址运算符&获取它们的地址。
    • 典型的右值包括常量、临时表达式、字面值等
    cppCopy codeint result = 5 + 3; // 5 + 3是右值
    int&& temp = 10;    // 10是右值(通过引用绑定)
    

C++11引入了右值引用(Rvalue References),允许我们对右值进行引用绑定,从而更灵活地处理右值。右值引用使用&&来声明:

cppCopy code
int&& rvalueRef = 5; // 右值引用绑定到右值

总体而言,左值和右值的概念在C++中与内存中的对象的生命周期和可修改性密切相关。左值通常是可以被取地址、有名字的对象,而右值通常是临时的、不可取地址的值。

使用 “&” 表示。但此种引用方式有一个缺陷,即正常情况下只能操作 C++ 中的左值,无法对右值添加引用int &c = 10; //错误,但允许使用常量左值引用操作右值const int &c = 10;

C++11 标准新引入了另一种引用方式,称为右值引用,用 “&&” 表示。&&右值引用(Rvalue reference)是指绑定到右值(Rvalue)的引用类型,通常使用&& 符号声明。

C++11右值引用(一看即懂) (biancheng.net)

std::move

std::move 是 C++ 中 <utility> 头文件中提供的一个函数模板。它主要用于将左值(Lvalues)转换为右值引用(Rvalue References),从而支持移动语义。移动语义是 C++11 引入的一项特性,它允许高效地将资源(如内存所有权)从一个对象转移到另一个对象,而不进行深拷贝。

std::queue<std::function<void()>> tasks;
auto task = tasks.front();与std::function<void()> task(std::move(tasks.front()));的特点和区别

auto task = tasks.front();

会将 task 初始化为 tasks 队列的前端元素的拷贝。这意味着 tasktasks.front() 的一个副本,而不会影响队列本身。

std::function<void()> task(std::move(tasks.front()));

在这里,std::move(tasks.front())tasks 队列的前端元素转换为右值引用,并且通过 std::function<void()> task(...) 的构造函数使用移动构造函数。这样做的主要优势是,如果 std::function 支持移动语义(通常是支持的),那么它可以更有效地转移 tasks.front() 中的资源而不进行不必要的复制。

在处理队列元素时,选择使用 std::move 取决于你是否希望在移动语义下进行操作以提高性能。使用 std::move 通常是在你明确知道你不再需要原始元素时,以及你希望避免不必要的复制时。

完美转发 std::forward<>

C++完美转发_c++ 条件转发-CSDN博客

定义:如果我们需要一种方法能够按照参数原来的类型转发到另一个函数,这种转发类型称为完美转发。

一个右值引用参数作为函数的形参,在函数内部再转发该参数的时候它已经变成一个左值,并不是他原来的类型:

当我们将一个右值引用传入函数时,他在实参中有了命名,所以继续往下传或者调用其他函数时,根据C++ 标准的定义,这个参数变成了一个左值。那么他永远不会调用接下来函数的右值版本,这可能在一些情况下造成拷贝。为了解决这个问题 C++ 11引入了完美转发,根据右值判断的推倒,调用forward 传出的值,若原来是一个右值,那么他转出来就是一个右值,否则为一个左值。
这样的处理就完美的转发了原有参数的左右值属性,不会造成一些不必要的拷贝。代码如下:

template<typename T>
void print(T& t) {
    t = 1;
    //std::cout << t << std::endl;
    std::cout << "lvalue" << std::endl;
}
template<typename T>
void print( T&& t) {
    t =2;
    /*std::cout <<t << std::endl;*/
    std::cout << "rvalue" << std::endl;
}

template<typename T>
void TestForward(T&& v) {
    print(v);
    std::cout << v << std::endl << std::endl;

    print(std::forward<T>(v));
    std::cout << v << std::endl << std::endl;
    
    print(std::move(v));
    std::cout << v << std::endl << std::endl;

}

int main() {
    TestForward(0);
    int x = 1;
    TestForward(x);
    TestForward(std::forward<int>(x));
    return 0;
}


在这里插入图片描述
函数中&&为万能引用,既左值、右值都能接收,但&作为函数形参时,只能接受左值。
在这里插入图片描述

简单线程池

www.seestudy.cn

#include<iostream>
#include<thread>
#include<condition_variable>
#include<queue>
#include<mutex>
#include<functional>
class ThreadPool
{
private:
	bool stop;
	std::queue<std::function<void()>> tasks;
	std::vector<std::thread> threads;

	std::mutex mtx;
	std::condition_variable cv;

public:
	ThreadPool(int numThreads) :stop(false) {
		for (int i = 0; i < numThreads; ++i) {
			std::cout << "thread" << i << std::endl;
			
			//threads.emplace_back([this]() {
			threads.push_back(std::thread([this]() {
				while (true) {
					std::unique_lock<std::mutex> lock(mtx);
					cv.wait(lock, [this]() { return !tasks.empty() || stop; });
					//cv.wait(lock, !tasks.empty()||stop);
					if (stop && tasks.empty()) return;
					//auto task = tasks.front();
					std::function<void()> task(std::move(tasks.front()));
					tasks.pop();
					lock.unlock();
					task();//执行任务,提前将任务bind成函数了,不用传参数
					
				}
				}));
		}
	}
	~ThreadPool() {
		{
			std::unique_lock<std::mutex> lock(mtx);
			stop = false;
		}
		for (auto& t : this->threads) {
			t.join();
		}
	}
	//左值是指可以放在等号左边的值,反之,只能位于赋值号右侧的表达式就是右值:常数、
	// 使用 "&" 表示。但此种引用方式有一个缺陷,即正常情况下只能操作 C++ 中的左值,无法对右值添加引用int &c = 10; //错误,但允许使用常量左值引用操作右值const int &c = 10;
	// C++11 标准新引入了另一种引用方式,称为右值引用,用 "&&" 表示。
	// &&右值引用(Rvalue reference)是指绑定到右值(Rvalue)的引用类型,通常使用&& 符号声明。右值是指不能被取地址的表达式,例如临时对象、表达式结果等等。
	// 和常量左值引用不同的是,右值引用还可以对右值进行修改
	//这里传入的是lambda表达式或者函数,
	template<typename F, typename ...Args>
	void enqueue(F&& f, Args&&... args) 
	{
		//std::function<void()> task(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
		std::function<void()> task(std::bind(f, args...));
		{
			std::unique_lock<std::mutex> lock(mtx);
			//tasks.emplace(std::move(task));
			tasks.emplace(task);
		}
		cv.notify_one();
	}


};

int main()
{
	ThreadPool tp(5);
	std::this_thread::sleep_for(std::chrono::microseconds(100));
	std::cout << "cjwxcc" << std::endl;
	std::this_thread::sleep_for(std::chrono::microseconds(10));
	for (int i = 0; i < 10; ++i)
	{
		auto task = [i]() {std::cout << "Task" << i << "is runing" << std::endl; };
		
		tp.enqueue(task);
	}
	return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嗯哼_Hello

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值