3

我想以多线程方式实现分支和绑定搜索。特别是,我想用它async来包装每个分支的搜索调用,然后等到某个线程给出答案,然后退出。(理想情况下,我想取消其他线程,但线程取消不在标准中)。这是一些简化的代码:

#include <iostream>
#include <random>
#include <future>
#include <thread>

using namespace std;

mt19937 rng;
uniform_int_distribution<unsigned> random_binary(0, 1);

bool search() {
  return static_cast<bool>(random_binary(rng));
}

#define N 10000

int main()
{
  rng.seed(42);

  std::vector<future<bool>> tasks;

  for (unsigned i=0; i<N; ++i)
    tasks.push_back(async(launch::async, search));

  // Don't want to wait sequentially here.
  for (unsigned i=0; i<N; ++i) {
    tasks[i].wait();
    if (tasks[i].get()) {
      cout << "i = " << i << "\n";
      break;
    }
  }
  return 0;
}

search()是搜索功能。它根据是否找到答案返回真/假。我返回一个随机答案以供说明。但问题的症结在于调用tasks[i].wait(). 现在,我正在按顺序等待任务完成。相反,我想做这样的事情:

auto x = wait_for_any(tasks.begin(), tasks.end());
x.get();
// cancel other threads.
// Profit?

什么是实现这一目标的好方法?

4

3 回答 3

8

std::future提供了一个valid()函数,可以让您检查结果是否可用而不阻塞,因此您可以使用它,例如在忙等待循环中:

std::future<bool>* res_future = 0;
for(size_t i = 0; ; i==tasks.size()?i=0:++i){
  // could add a timeout period to not completely busy-wait the CPU
  if(tasks[i].wait_for(std::chrono::seconds(0)) == std::future_status::ready){
    res = &tasks[i];
    break;
  }
}

bool res = res_future->get();

std::future为了使这样的任务更容易,建议添加一个在结果可用时.then(func_obj)异步调用 的方法,您可以在其中设置标志或其他东西。func_obj

遗憾的是,我不知道可能wait_for_any以上述任何其他方式实施的方法。:/

template<class FwdIt>
std::future<bool> wait_for_any(FwdIt first, FwdIt last)
{
  return std::async([=]{
    for(FwdIt cur(first); ; cur==last?cur=first:++cur){
    // could add a timeout period to not completely busy-wait the CPU
    if(cur->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
      return cur->get();
  });
}

线程销毁通常通过合作取消来完成。

PS:如果结果不可用,std::future<T>::get()将自动。wait()

于 2012-08-10T22:43:37.220 回答
6

安排所有任务都可以访问相同condition_variablemutex、 和bool。这可以通过使这些全局变量或每个任务运行成员函数的成员数据来完成,或者您可以将它们std::ref作为参数传递给任务创建函数。

在开始任何任务之前初始化boolto 。not_found然后主线程启动任务并等待condition_variable. 然后搜索器任务进行搜索。当他们搜索时,他们偶尔会检查bool(可能带有原子负载)以查看它是否已设置为found. 如果有,搜索线程立即返回。

当一个线程找到结果时,它将设置boolfound并发出信号condition_variable。这将唤醒主线程并有效地取消其余的搜索任务。然后,主线程可以加入、分离、放弃等所有搜索任务。如果您没有 main 显式加入搜索器任务,最好安排所有搜索器任务在 main 退出之前结束。

没有投票。无需等待死胡同搜索。唯一的临时部分是弄清楚搜索者任务检查bool. 我建议对这部分进行性能测试。

于 2012-08-10T23:17:29.653 回答
0

我将采取的方法是让 main 函数创建 astd::promise然后作为对将要完成工作的各种线程的引用传递。一旦获得结果,每个工作线程将使用std::promise它们共享的所有线程。set_value()

哪个工作线程首先到达那里将能够发送结果,而其他线程在尝试使用set_value()并且已经设置时会抛出异常。

在我正在使用的源代码框架中,但如果我们可以分离自治线程而不创建不用于任何东西std::async的附加部分,那就太好了。std::promise

所以代码骨架看起来像:

#include <iostream>
#include <thread>  // std::thread is defined here
#include <future>  // std::future and std::promise defined here

bool search(int args, std::promise<int> &p) {

    // do whatever needs to be done

    try {
        p.set_value(args);
    }
    catch (std::future_error & e) {
        // std::future_errc::promise_already_satisfied
    }
    return true;
}
int main(int argc, char * argv[])
{
    std::promise<int> myProm;    
    auto fut = myProm.get_future();

    for (int i = 1; i < 4; i++) {
        std::async(std::launch::async, search, i, std::ref(myProm));
    }

    auto retVal = fut.get();
    return 0;
}
于 2016-01-23T03:30:01.510 回答