C++ C++;:std::thread的简单返回值?
对于win32线程,我有一个直接的C++ C++;:std::thread的简单返回值?,c++,multithreading,C++,Multithreading,对于win32线程,我有一个直接的GetExitCodeThread(),它为我提供了线程函数返回的值。我正在为std::thread(或boost threads) 据我所知,这可以通过futures实现,但具体如何实现呢?请参见C++11 futures 明确使用线程和未来: #include <thread> #include <future> void func(std::promise<int> && p) { p.set_
GetExitCodeThread()
,它为我提供了线程函数返回的值。我正在为std::thread
(或boost threads)据我所知,这可以通过futures实现,但具体如何实现呢?请参见C++11 futures 明确使用线程和未来:
#include <thread>
#include <future>
void func(std::promise<int> && p) {
p.set_value(1);
}
std::promise<int> p;
auto f = p.get_future();
std::thread t(&func, std::move(p));
t.join();
int i = f.get();
#include <thread>
#include <future>
int func() { return 1; }
std::future<int> ret = std::async(&func);
int i = ret.get();
我无法评论它是否能在所有平台上运行(它似乎能在Linux上运行,但不能在带有GCC 4.6.1的Mac OSX上为我构建)。我想说:
#include <thread>
#include <future>
int simplefunc(std::string a)
{
return a.size();
}
int main()
{
auto future = std::async(simplefunc, "hello world");
int simple = future.get();
return simple;
}
#包括
#包括
int simplefunc(标准::字符串a)
{
返回a.size();
}
int main()
{
auto future=std::async(simplefunc,“hello world”);
int simple=future.get();
回归简单;
}
请注意,async甚至会传播从线程函数抛出的任何异常,这取决于您对“简单”的定义
使用期货当然会在几行C++中发挥神奇作用,但我发现,为一个简单的应用劫持一个并行处理的机制是有争议的。 未来在多核CPU上最有意义,在多核CPU上,它们允许进程启动非同步任务,这将从其他内核获取计算能力(撇开一个事实不谈,找到一组足够大、值得付出努力的无关数据也不是一件小事)
我称之为语法驱动的软件设计,使用整个机制作为一种解决方法来检索一个int返回值。它很好地展示了C++11的多功能性,但它确实在语法糖霜下隐藏了大量的资源消耗 如果不使用其他内核作为原始电源,那么如果您不打算在完成之前与线程通信,那么创建线程有什么意义呢?因为如果你这样做了,从中获取任何状态,无论是在终止时还是任何时候,都将是一件微不足道的事情,你甚至一开始都不会想到使用期货 除了(有争议的)便利性或美感之外,这些技巧在功能上实现了什么可以被认为足够有用以抵消隐藏成本的功能 阅读这些答案时,如果没有适当的多任务背景,新来的孩子们可能会被经常使用这些低效的机制所吸引。
如果出现更多的“综合征”,这只会污染未来的软件。使用C++11线程,就无法获得线程退出时的返回值,而使用
pthread\u exit(…)时,则无法获得该返回值。
您需要使用C++11Future
来获取返回值。Future是使用templated参数创建的,其中模板接受返回值(内置于用户定义类型中)
您可以使用future::get(..)
函数在另一个线程中获取该值
使用future
的一个好处是,您可以检查返回值的有效性,也就是说,如果返回值已经被获取,您可以通过使用future::isValid(…)
函数检查有效性来避免意外调用get()
下面是您将如何编写代码
#include <iostream>
#include <future>
using namespace std;
auto retFn() {
return 100;
}
int main() {
future<int> fp = async(launch::async, retFn);
if(fp.valid())
cout<<"Return value from async thread is => "<<fp.get()<<endl;
return 0;
}
我认为引用变量的读取更直观
std::mutex m;
void threadFunction(int& val) {
std::lock_guard<std::mutex> guard(m);
val = 5;
}
int x = 0;
std::thread theThread(threadFunction, std::ref(x));
theThread.join();
std::cout << x << std::endl;
// prints 5
std::mutexm;
无效线程函数(int&val){
标准:锁紧装置(m);
val=5;
}
int x=0;
std::thread线程(threadFunction,std::ref(x));
theThread.join();
std::cout使用std::ref
传递指向线程的引用/指针
async
比这更好,但就科学而言,它可以做到:
void myfunc_reference(int& i);
std::thread(myfunc_reference, std::ref(output));
我怀疑async
的实现必须在幕后为我们做一些事情,这基本上就是您在pthread
后端必须做的事情:
当然,您必须确保变量的生存期持续到线程返回为止
下面的可运行代码示例比较了async和此更糟糕的方法:
main.cpp
#include <cassert>
#include <future>
#include <iostream>
#include <thread>
#include <vector>
int myfunc(int i) {
return i + 1;
}
void myfunc_reference(int& i) {
i = myfunc(i);
}
int main() {
unsigned int nthreads = 4;
std::vector<int> inputs{1, 2, 3, 4};
std::vector<int> outputs_expect{2, 3, 4, 5};
// future and sync. Nirvana. When you are not fighting to death with types:
// https://stackoverflow.com/questions/10620300/can-stdasync-be-use-with-template-functions
{
std::vector<std::future<int>> futures(nthreads);
std::vector<int> outputs(nthreads);
for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
futures[i] = std::async(
myfunc,
inputs[i]
);
}
for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
outputs[i] = futures[i].get();
}
assert(outputs_expect == outputs);
}
// Reference arguments.
//
// Annoying because requires:
//
// - wrapping the return function to accept references
// - keeping an array of outputs
// - std::ref
{
std::vector<std::thread> threads(nthreads);
std::vector<int> inouts(inputs);
for (decltype(threads)::size_type i = 0; i < nthreads; ++i) {
threads[i] = std::thread(myfunc_reference, std::ref(inouts[i]));
}
for (auto& thread : threads) {
thread.join();
}
assert(outputs_expect == inouts);
}
}
在Ubuntu 19.04中测试。这里是一个更具体的例子
函数使用回调参数模拟下载,以显示进度并取消下载
namespace __HeavyWork
{
int SimulateDownload(std::function<int(int)> dlCallBack)
{
for (size_t i = 0; i < 100; i++)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if (dlCallBack(i) == -1)
{
return i;
}
}
return 100;
}
}
namespace\uuuuuu重量级工作
{
int模拟下载(std::函数dlCallBack)
{
对于(尺寸i=0;i<100;i++)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if(dlCallBack(i)=-1)
{
返回i;
}
}
返回100;
}
}
我们想获得下载状态
#include <thread>
#include <future>
void test()
{
auto simulateCancellation = []()->bool {
static bool b = true;
if (b)
{
srand((unsigned int)time(NULL));
b = false;
}
return (rand() % 7) == 0;
};
auto funDLCallback = [&](int i)->int {
if (simulateCancellation())
{
return -1;
}
cout << "download: " << i << endl;
return i;
};
auto funDownload = [&](std::promise<int> && p) {
p.set_value(__HeavyWork::SimulateDownload(funDLCallback));
};
std::promise<int> p;
auto f = p.get_future();
std::thread t(funDownload, std::move(p));
//dlg.doModal();
t.join();
cout << "return value: " << f.get() << endl;
}
#包括
#包括
无效测试()
{
自动模拟取消=[]()->bool{
静态布尔b=真;
如果(b)
{
srand((无符号整数)时间(NULL));
b=假;
}
返回值(rand()%7)=0;
};
自动资金回拨=[&](int i)->int{
如果(模拟取消())
{
返回-1;
}
这不会以std::system\u错误终止吗(请参阅),或者这是IdeOne的一个限制?我只是在键入它,因为我自己的答案被异常所转移:)@sehe通常这些沙盒环境不允许启动线程。@sehe很像是在Linux机器上,在编译时没有-pthread
。Forfunc() & &代码>而不是<代码>和<代码>?(也注意到你仔细地调用了<代码> STD::移动(p)< /COD>,所以这看起来是有意的。)Kevialpe(我在5年前写的,我多年没有写过C++,所以我猜我过去在这里做了什么……基本上,promise值是在另一个线程中设置的。promise是不可复制的,因此您不能通过值传递它(首先它是可复制的是没有意义的)。而且因为堆栈值可能超出范围,所以您也不能通过引用传递它。所以您需要转换
namespace __HeavyWork
{
int SimulateDownload(std::function<int(int)> dlCallBack)
{
for (size_t i = 0; i < 100; i++)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if (dlCallBack(i) == -1)
{
return i;
}
}
return 100;
}
}
#include <thread>
#include <future>
void test()
{
auto simulateCancellation = []()->bool {
static bool b = true;
if (b)
{
srand((unsigned int)time(NULL));
b = false;
}
return (rand() % 7) == 0;
};
auto funDLCallback = [&](int i)->int {
if (simulateCancellation())
{
return -1;
}
cout << "download: " << i << endl;
return i;
};
auto funDownload = [&](std::promise<int> && p) {
p.set_value(__HeavyWork::SimulateDownload(funDLCallback));
};
std::promise<int> p;
auto f = p.get_future();
std::thread t(funDownload, std::move(p));
//dlg.doModal();
t.join();
cout << "return value: " << f.get() << endl;
}