线程内嵌套 std::thread 的错误会引发错误

Error nested std::thread inside a thread throws an error

我试图通过这个简单的测试在另一个线程中创建一个嵌套线程,但它总是失败。尝试删除这个嵌套函数,代码本身运行良好。

代码example/test:

#include <thread>
#include <iostream>
#include <vector>

void simple() {  std::cout << "\nNested Thread";  }

void function(int number, int* sum, std::vector<std::thread>& thread_group) {
    *sum += number;

    // Starting this nested function simple() in a thread causes errors.
    // The problem occurs even when there's only a single iteration of the loop.
    // Without it the code works fine, even with 10000 iterations.
    std::thread ct(simple);
    thread_group.push_back(std::move(ct));
}

int main(){
    // Container for storing threads
    std::vector<std::thread> thread_group;
    int sum = 0;
    for (int n = 1; n <= 10; n++) {
        std::thread t(function, n, &sum, std::ref(r), std::ref(thread_group));
        // Add the newly created thread to the container
        thread_group.push_back(std::move(t));
    }
    // Wait for all threads to finish
    join_all(thread_group);
    return 0;
}

话虽这么说,我需要找到一种方法来调用一个独立的函数,该函数可以 运行 而不会阻止其余代码的执行。线程或其他一些多处理方式在我的程序中非常重要,因为每个函数都是递归的,并不断调用具有不同参数的自身的多个副本,直到满足条件。

我不知道在 std::thread 库中是否可行。尝试使用 Poco 和 boost,但遇到了其他问题,因此决定坚持使用 std::thread。

我在 Windows 10 上使用 Visual Studio 2022。

您正在同时从多个线程读取和写入 sumthread_group。一个简单的解决方案是确保一次只有一个线程可以访问它们,方法是使用 std::mutex 并在访问这些变量时将其锁定。您还需要确保所有线程在 thread_group 被销毁之前完成工作。我添加了一个计数器和一个 std::condition_variable 来处理这个问题。

示例(使用 C++20 std::jthreads 而不必调用 non-existing join_all 函数):

#include <condition_variable>
#include <iostream>
#include <list>     // using list instead of vector to avoid realloc
#include <mutex>
#include <thread>
#include <vector>

using container = std::list<std::jthread>;

void simple() {  std::cout << "Nested Thread\n";  }

void function(int& counter, std::mutex& mtx,
              std::condition_variable& cv, container& thread_group)
{
    std::lock_guard lock(mtx);
    thread_group.emplace_back(simple);
    ++counter;       // so that main thread can check that all is done
    cv.notify_one(); // signal main that the work is done
}

int main(){
    // Container for storing threads
    container thread_group;
    std::mutex mtx;
    std::condition_variable cv;

    int starting_threads = 10;
    int counter = 0;
    for (int n = 1; n <= starting_threads; n++) {
        std::lock_guard lock(mtx); // lock while adding thread
        // Add thread to the container
        thread_group.emplace_back(function, std::ref(counter), std::ref(mtx),
                                  std::ref(cv), std::ref(thread_group));
    }   
    
    std::unique_lock lock(mtx);
    // wait until all threads are done with thread_group
    // before letting thread_group go out of scope and get
    // destroyed
    while(counter < starting_threads) cv.wait(lock);

    std::cout << thread_group.size() << '\n';

    // wait for all threads to finish (jthread's auto-join)
}

可能的输出:

Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
20
Nested Thread