假设我有一个函数double someRandomFunction(int n)
,该函数需要一个整数并返回双精度值,但是从某种意义上说它是随机的,因为它会尝试使用随机的东西来提出解决方案,因此即使您使用相同的参数运行该函数,有时它可能需要10秒钟才能完成,而其他40秒钟才能完成。
double someRandomFunction(int n)
函数本身是黑盒函数的包装。所以someRandomFunction
需要一段时间才能完成,但是我在黑盒的主循环中没有控制权,因此,由于繁重的计算是在黑色中进行,因此我无法真正检查线程中的标志变量框功能。
我想启动10个调用该函数的线程,并且我对第一个首先完成的线程的结果感兴趣。我不在乎是哪一个,这些线程只需要1个结果。
我找到了以下代码:
std::vector<boost::future<double>> futures;
for (...) {
auto fut = boost::async([i]() { return someRandomFunction(2) });
futures.push_back(std::move(fut));
}
for (...) {
auto res = boost::wait_for_any(futures.begin(), futures.end());
std::this_thread::yield();
std::cout << res->get() << std::endl;
}
哪个是我所寻找的最接近的,但我仍然看不到如何使我的程序终止一个线程,直到一个线程返回了解决方案。
我想等待一个线程结束,然后继续执行那个线程的结果以继续执行程序(即,我不想在获得单个结果后终止程序,但是我会喜欢将其用于剩余的程序执行。)
同样,我想启动10个调用someRandomFunction
的线程,然后等待一个线程首先完成,获得该线程的结果并停止所有其他线程,即使它们没有完成工作
答案 0 :(得分:2)
如果提供给黑匣子的数据结构具有一些明显的开始和结束值,则使它尽早完成的一种方法可能是在计算时更改结束值。如果您误解了黑框必须如何处理数据,这当然可能会引起各种麻烦,但是如果您有把握的话,它就可以工作。
main产生100个外部线程,每个产生一个调用黑盒的内部线程。内部线程接收黑盒结果,并通知所有等待线程完成。外层线程等待 any 内层线程完成,然后修改其自己的黑盒数据以诱使它完成。
没有轮询(除了虚假的唤醒循环),也没有分离的线程。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <chrono>
// a work package for one black-box
struct data_for_back_box {
int start_here;
int end_here;
};
double blackbox(data_for_back_box* data) {
// time consuming work here:
for(auto v=data->start_here; v<data->end_here; ++v) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// just a debug
if(data->end_here==0) std::cout << "I was tricked into exiting early\n";
return data->end_here;
}
// synchronizing stuff and result
std::condition_variable cv;
std::mutex mtx;
bool done=false;
double result;
// a wrapper around the real blackbox
void inner(data_for_back_box* data) {
double r = blackbox(data);
if(done) return; // someone has already finished, skip this result
// notify everyone that we're done
std::unique_lock<std::mutex> lock(mtx);
result = r;
done=true;
cv.notify_all();
}
// context setup and wait for any inner wrapper
// to signal "done"
void outer(int n) {
data_for_back_box data{0, 100+n*n};
std::thread work(inner, &data);
{
std::unique_lock<std::mutex> lock(mtx);
while( !done ) cv.wait(lock);
}
// corrupt data for blackbox:
data.end_here = 0;
// wait for this threads blackbox to finish
work.join();
}
int main() {
std::vector<std::thread> ths;
// spawn 100 worker threads
for(int i=0; i<100; ++i) {
ths.emplace_back(outer, i);
}
double saved_result;
{
std::unique_lock<std::mutex> lock(mtx);
while( !done ) cv.wait(lock);
saved_result = result;
} // release lock
// join all threads
std::cout << "got result, joining:\n";
for(auto& th : ths) {
th.join();
}
std::cout << "result: " << saved_result << "\n";
}