Day4 创建一个能返回结果的线程

同步任务与异步任务:

        同步任务:发出一个功能调用时,在没得到结果前,该调用永不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。个人理解是就像thread的join(),你不执行完该线程就不能继续执行主函数。

        异步任务:当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。个人理解同thread的detach(),你不用执行完就可以继续进行主程序,只是他还会在执行完后通知调用者。

async 与future

async用于创建异步任务并返回值,future用于获取返回值(通过get()函数获取结果),都在头文件<future>中。

future有两个主要使用的函数,一个是wait(),另一个是get()。wait()可以使进程等待到线程执行完毕(同join()),可以与get()一起使用(虽然没啥必要),可以调用多次。get()函数用于获取线程的返回值,且进程会卡在get函数直到异步任务返回值;而且get函数只能调用一次,因为get()会将future中的值给移动走,如果想不移动走而是复制一个值出来的话要用share_future。

async有两个重载函数,区别是有无launch参数。future是一个类,主要是调用其中的get函数来获取返回值。

用法一:future<返回值类型> 对象名 = async(具有返回值的函数名, 函数参数);

#include<iostream>
#include<future>
#include<windows.h>
using namespace std;

class A {
private:
	mutex mymutex;
	condition_variable mycond;
	int i = 5;

public:
	int hanshu() {
		cout << "调用函数" << endl;
		Sleep(5000);      //等待5秒,用来证明进程会在get时等待。
		return 4;
	}
};

int main() {
	A a;
	future<int> future1 = async(&A::hanshu, &a);
	cout << "111" << endl;
    future1.wait();
    int t = future1.get();
	cout << t << endl;
	cout << "222" << endl;
	return 0;
}

用法二:future<返回值类型> 对象名 = async(launch型的参数,具有返回值的函数名, 函数参数);

        用法一其实就是调用用法二,但launch的参数为(launch::async | launch::deferred)它会在系统资源不够创建一个新线程时创建一个同步任务(在主线程中运行),否则创建一个异步任务。

        使用launch::deferred时会直到调用get()或wait()函数时才调用该线程。

        使用launch::async时会在创建时调用该线程。

#include<iostream>
#include<future>
#include<windows.h>
using namespace std;

class A {
private:
	mutex mymutex;
	condition_variable mycond;
	int i = 5;

public:
	int hanshu() {
		cout << "调用函数" << endl;
		Sleep(5000);      //等待5秒,用来证明进程会在get时等待。
		return 4;
	}
};

int main() {
	A a;
	//future<int> future1 = async(launch::async, &A::hanshu, &a);	
    future<int> future1 = async(launch::deferred, &A::hanshu, &a);
	cout << "111" << endl;
    future1.wait();
    int t = future1.get();
	cout << t << endl;
	cout << "222" << endl;
	return 0;
}

在上面我们说过,future的get函数会把值从里面移走,使得只能get一次,但当我们需要在多个线程调用这个返回值时,就需要使用shared_future了,它因为get是复制,所以可以get多次,创建如下。shared_future<返回值类型> 名称(move(已绑定线程的future类型))或者调用future的share函数,具体情况如下。

#include<iostream>
#include<future>
#include<algorithm>
using namespace std;

int hanshu() {
    cout << "调用函数" << endl;
    return 3;
}

int main() {
    future<int> future1 = async(hanshu);
    //shared_future<int> sfuture1(future1.share());
    shared_future<int> sfuture1(move(future1));
    cout << sfuture1.get() << endl;
    cout << sfuture1.get() << endl;

    return 0;
}

future的其他成员函数:wait_for、wait_until;这两个函数都需要一个参数作为等待时间,返回值是一个枚举类型future_status,有三种:timeout(超时,即在等待时间内线程未执行完毕)、ready(已完成,即在等待时间内线程已执行完毕,立即返回,不用等到等待时间)、deferred(线程参数选择了deferred,并未开始执行)。

wait_for与wait_until区别:

        参数类型不同,wait_for的参数常用格式为:chrono::seconds(i)、chrono::milliseconds(i),即等待i秒或者等待i毫秒;wait_until的参数格式为:chrono::system_clock::time_point,即未来的某个时间点。

#include<iostream>
#include<future>
using namespace std;

int hanshu(int a) {
	cout << "线程开始执行" << endl;
	return a;
}

int main() {
	future<int> future1 = async(hanshu, 5);
//wait_for
	future_status stu = future1.wait_for(chrono::milliseconds(5));
	if (stu == future_status::deferred) {
		cout << "线程未执行" << endl;
	}
	else if (stu == future_status::ready) {
		cout << "等待时间内线程执行完毕" << endl;
	}	
	else{
		//stu == future_status::timeout
		cout << "等待时间内线程未执行完毕" << endl;
	}
//wait_until
	std::chrono::system_clock::time_point two_seconds_passed = std::chrono::system_clock::now() + std::chrono::seconds(2);  //后面加的时间就是等待时间
	future_status stu1 = future1.wait_until(two_seconds_passed);
	if (stu1 == future_status::deferred) {
		cout << "线程未执行" << endl;
	}
	else if (stu1 == future_status::ready) {
		cout << "等待时间内线程执行完毕" << endl;
	}
	else {
		//stu1 == future_status::timeout
		cout << "等待时间内线程未执行完毕" << endl;
	}

	return 0;
}

packaged_task:

        packaged_task在<future>头文件中,是一个类模板,参数是可调用对象(可以是普通函数也可以是lambda函数或函数对象,但类的成员函数好像不行,希望有大佬能告知),可以将各种可调用对象包装起来作为线程入口便于其异步调用。

创建如下:std::packaged_task<函数返回值类型(函数参数类型)> 对象名(可调用对象);

string hanshu(int shu, int v) {
	cout << "调用函数, id = " << this_thread::get_id() << endl;
	//Sleep(5000);
	string t = to_string(shu);
	return t;
}

int main() {
	std::packaged_task<string(int, int)> pack1(hanshu); //这里string代表函数返回值类型,两个int代表参数类型。
    return 0;
}

单纯创建只是将函数封装起来,要调用的话还是需要使用thread。由于packaged_task不可复制,但可以移动,所以在调用时要用move或者ref

string hanshu(int shu, int v) {
	cout << "调用函数, id = " << this_thread::get_id() << endl;
	//Sleep(5000);
	string t = to_string(shu);
	return t;
}

int main() {
	std::packaged_task<string(int, int)> pack1(hanshu);
    //调用包装起来的函数,记得要用ref或move
	//thread thread1(ref(pack1), 3, 3);      
    thread thread1(move(pack1), 3, 3);  
	thread1.join();
    return 0;
}

thread只能让函数运行起来,要获取返回值还是需要future。注意,如果thread使用的是move的话,future要在move前先绑定pack1(即在thread前调用get_future()),shared_future同理.

string hanshu(int shu, int v) {
	cout << "调用函数, id = " << this_thread::get_id() << endl;
	//Sleep(5000);
	string t = to_string(shu);
	return t;
}

int main() {
	std::packaged_task<string(int, int)> pack1(hanshu);
	//future<string> future1 = pack1.get_future(); //如果是move的话要放在他前面哦
	thread thread1(ref(pack1), 3, 3);
	thread1.join();
	future<string> future1 = pack1.get_future();  //先调用packaged_task中的get_future函数将其绑定在future1中。
	//shared_future<string> future1 = pack1.get_future();     //不经过future直接绑定到shared_future上
	shared_future<string>future2(move(future1));              //先绑定到future上,再移动到shared_future上,注意,移动后future就没有绑定线程,即不能get了 
	//cout << future1.get() << endl;        //通过get获取返回值
	cout << future2.get() << endl;        //通过get获取返回值
	return 0;
}

promise :

        promise在头文件<future>中,是一个类模板,可以在一个线程中保存某个值(使用set_value()),然后在另一个线程中取出(使用get_future()绑定后通过get()取出),常用的成员函数有set_value();

#include<iostream>
#include<thread>
#include<future>
using namespace std;

void hanshu1(promise<int> &cunchu, int a) { //由于要存储值所以要用引用
	cunchu.set_value(a);
}

void hanshu2(future<int> &future1) {
	int a = future1.get();
	cout << "hanshu1线程中存储的数是" << a << endl;
}

int main() {
	promise<int> cunchu;
	thread thread1(hanshu1, ref(cunchu), 3);  //形参有引用,实参用ref
	future<int> future1 = cunchu.get_future();   //绑定
	thread thread2(hanshu2, ref(future1));  

	thread1.join();
	thread2.join();

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值