将输出流对象和其他参数传递给多个线程

Passing output stream object and other arguments to multiple threads

我正在尝试将多个参数(其中之一是 ofstream 对象)传递给使用 C++11 标准的多个线程。

我想传递一个 ofstream 对象,因为我希望每个线程都写入不同的输出文件。

我正在以这种方式初始化线程和输出流:

std::thread execution_threads[NUMBER_OF_THREADS]; // creating multiple empty threads
std::ofstream output_files[NUMBER_OF_THREADS]; // Empty output streams
// Opening and initializing the output files

每个线程执行一个带有两个参数的函数:

void execution(int thread_id, std::ofstream& output_file)

所以我环顾四周,我在 C++11 中读到当函数 func 有多个参数时 a,b,c,d 不需要使用 struct你可以通过写 std::thread t(func, a,b,c,d); 来传递它们。所以我写了这个循环来启动线程:

for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
    execution_threads[i] = std::thread(execution, i, output_files[i]);
}

问题是此代码无法编译并出现此错误:

Call to implicitly-deleted copy constructor of
'typename decay<basic_ofstream<char, char_traits<char> > &>::type'
(aka 'std::__1::basic_ofstream<char, std::__1::char_traits<char> >')

而如果我以这种方式使用 struct 作为输入,一切正常:

// Struct definition
struct thread_input {
    int thread_id;
    std::ofstream& output_file;
};

// This is the function that now has only one argument
void execution(struct thread_input input)

// And this is the loop that launches the threads
for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
    struct thread_input input = {i, output_files[i]};
    execution_threads[i] = std::thread(execution, input);
}

// join() functions for each thread and end of the program

通过这种方式,一切都可以正常编译并完美运行。但是我真的不明白为什么编译器告诉我如果我使用其他方法我正在尝试使用已删除的复制构造函数。

感谢您的帮助。

std::thread 存储其参数的副本。当你向它传递一个不可复制的对象时,如 std::ofstream 它会抱怨。

你有两个选择:

1) 不要存储 std::ofstream 个对象的数组;只需让您的线程存储自己的流即可。在这种情况下,不需要复制流(只是移动,这很好):

for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
    execution_threads[i] = std::thread(execution, i, std::ofstream{});
                                                   //^^^^^^^^^^^^^^^ anonymous temporary
}

当然,在这种情况下,您可以让线程构造自己的流(也许只传入文件名)。

2) 将 std::reference_wrapper<std::ofstream> 传递给您的线程。 std::reference_wrapper<T> 是一个包含对 T 的引用并隐式转换为 T& 的对象,因此您最终只会复制引用而不是流本身。您可以使用 std::ref 工厂来推断 T 并减少输入:

for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
    execution_threads[i] = std::thread(execution, i, std::ref(output_files[i]));
                                                   //^^^^^^^^ std::ref added
}

这给您留下了传递包含 std::ofstream& 的结构所具有的所有相同的所有权和生命周期问题(毕竟,这就是 std::reference_wrapper 的全部)。由您来确保您的 output_files 数组在您的所有线程都完成它之前仍然存在。