簡體   English   中英

std :: thread:如何等待(join)任何給定的線程完成?

[英]std::thread: How to wait (join) for any of the given threads to complete?

例如,我有兩個線程, t1t2 我想等t1 t2完成。 這可能嗎?

如果我有一系列線程,比如說std::vector<std::thread> ,我該怎么辦呢?

總是使用std::condition_variable 等待並通知例如

std::mutex m;
std::condition_variable cond;
std::atomic<std::thread::id> val;

auto task = [&] {
    std::this_thread::sleep_for(1s); // Some work

    val = std::this_thread::get_id();
    cond.notify_all();
};

std::thread{task}.detach();
std::thread{task}.detach();
std::thread{task}.detach();

std::unique_lock<std::mutex> lock{m};
cond.wait(lock, [&] { return val != std::thread::id{}; });

std::cout << "Thread " << val << " finished first" << std::endl;

注意: val不一定代表首先完成的線程,因為所有線程幾乎同時完成並且發生覆蓋migh,但它僅用於此示例的目的。

不,在C ++ 11的線程庫中沒有等待多個對象等效。

如果要等待一組操作中的第一個操作,請考慮讓它們提供一個線程安全的生產者 - 消費者隊列。

是我發布的包含threaded_queue<T>的帖子。 將線程的工作產品交付到這樣的隊列中。 讓消費者閱讀另一端。

現在有人可以一次等待多個線程的(工作產品)。 或一個線程。 或GPU着色器。 或者通過RESTful Web界面交付工作產品。 你不在乎。

線程本身應該由std::thread類的線程池或其他更高級別的抽象來管理,因為std::thread使得面向客戶端的線程抽象不佳。

template<class T>
struct threaded_queue {
  using lock = std::unique_lock<std::mutex>;
  void push_back( T t ) {
    {
      lock l(m);
      data.push_back(std::move(t));
    }
    cv.notify_one();
  }
  boost::optional<T> pop_front() {
    lock l(m);
    cv.wait(l, [this]{ return abort || !data.empty(); } );
    if (abort) return {};
    auto r = std::move(data.back());
    data.pop_back();
    return r;
  }
  void terminate() {
    {
      lock l(m);
      abort = true;
      data.clear();
    }
    cv.notify_all();
  }
  ~threaded_queue()
  {
    terminate();
  }
private:
  std::mutex m;
  std::deque<T> data;
  std::condition_variable cv;
  bool abort = false;
};

我在C ++ 17中使用std::optional而不是boost::optional 它也可以用unique_ptr或許多其他結構替換。

輪詢等待很容易:

#include<iostream>
#include<thread>
#include<random>
#include<chrono>
#include<atomic>

void thread_task(std::atomic<bool> & boolean) {
    std::default_random_engine engine{std::random_device{}()};
    std::uniform_int_distribution<int64_t> dist{1000, 3000};
    int64_t wait_time = dist(engine);
    std::this_thread::sleep_for(std::chrono::milliseconds{wait_time});
    std::string line = "Thread slept for " + std::to_string(wait_time) + "ms.\n";
    std::cout << line;
    boolean.store(true);
}

int main() {
    std::vector<std::thread> threads;
    std::atomic<bool> boolean{false};
    for(int i = 0; i < 4; i++) {
        threads.emplace_back([&]{thread_task(boolean);});
    }
    std::string line = "We reacted after a single thread finished!\n";
    while(!boolean) std::this_thread::yield();
    std::cout << line;
    for(std::thread & thread : threads) {
        thread.join();
    }
    return 0;
}

我在Ideone.com上獲得的示例輸出:

Thread slept for 1194ms.
We reacted after a single thread finished!
Thread slept for 1967ms.
Thread slept for 2390ms.
Thread slept for 2984ms.

這可能不是最好的代碼,因為輪詢循環不一定是最佳實踐,但它應該作為一個開始。

沒有標准的等待多線程的方法。

您需要使用Windows上的WaitForMultipleObjects等特定於操作系統的功能。 僅限Windows的示例:

HANDLE handles[] = { t1.native_handle(), t2.native_handle(),  };
auto res = WaitForMultipleObjects(2 , handles, FALSE, INFINITE);

有趣的是,當std::when_any將被標准化時,人們可以做一個標准但浪費的解決方案:

std::vector<std::thread> waitingThreads;
std::vector<std::future<void>> futures;
for (auto& thread: threads){
    std::promise<void> promise;
    futures.emplace_back(promise.get_future());
    waitingThreads.emplace_back([&thread, promise = std::move(promise)]{
         thread.join();
         promise.set_value();
    });
}

auto oneFinished = std::when_any(futures.begin(), futures.end());

非常浪費,仍然沒有,但標准。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM