为什么我在 C++ 线程函数调用中得到重复值?

Why am I getting duplicate values in a C++ thread function call?

我很好奇我在这里做错了什么。我有以下功能:

indexer.h:

class DtIndexer {
public:
    static void ThreadedIndex(string folderPath);

indexer.cpp

void DtIndexer::ThreadedIndex(string folderPath) {
    cout << "\t-> Indexing Folder: " << folderPath << endl;
    cout << "\t->> Done..." << endl;
}

以及我创建线程的调用:

void DtIndexer::UpdateIndex(DatabaseData &data, bool isCreate) {
    vector<thread> threadList;

    for (string &s: data.FilePaths) {
        const char *folder = GetFolderPath(s, data.IncludeSubFolders);
        cout << "\t-> Adding Folder to Thread: " << folder << endl;
        threadList.emplace_back(thread(ThreadedIndex, folder));
    }

    for_each(threadList.begin(), threadList.end(), mem_fn(&thread::join));
}

我的输出是这样的:

-> Adding Folder to Thread: /index_2185<+>

-> Adding Folder to Thread: /index_1065<+>

-> Indexing Folder: /index_1065<+>

->> Done...

-> Indexing Folder: /index_1065<+>

->> Done...

现在,我很确定它必须处理方法的静态,但如果我删除静态,我会得到这个:

error: invalid use of non-static member function ‘void DtIndexer::ThreadedIndex(std::__cxx11::string)’ threadList.emplace_back(thread(ThreadedIndex, folder));

此外,如果我删除 static 并将函数添加到线程,如下所示:

threadList.emplace_back(thread(&DtIndexer::ThreadedIndex, folder));

我得到:

required from here /usr/include/c++/6/functional:1286:7: error: static assertion failed: Wrong number of arguments for pointer-to-member static_assert(_Varargs::value

我对 C++ 还是很陌生,因此,我们将不胜感激任何建议。

替换

const char *folder = GetFolderPath(s, data.IncludeSubFolders);

std::string folder( GetFolderPath(s, data.IncludeSubFolders) );

线程首先按值复制参数,然后复制一个 const char*,它可能指向 GetFolderPath 函数中的静态缓冲区。对于您执行的每次调用,该缓冲区将被覆盖,因此从中读取的线程可能会或可能不会得到您期望的结果。

请注意,您不需要执行 emplace_back(std::thread(...,因为您作为参数写入 emplace_back 的内容将转发给您的 vector 持有的类型的构造函数,其中这个案例是std::thread。你也不需要使线程函数 static 除非你真的想要。您可以从 lambda 开始,通过复制捕获 thisfolder。您可能会注意到的另一件事是,当许多线程同时写入 std::cout 时,输出会出现乱码。您可以使用 std::mutexstd::lock_guard.

防止多个线程同时访问公共资源(如 std::cout

这是你的 class 的一个版本,带有非静态线程方法和 std::cout 的保护:

#include <iostream>
#include <vector>
#include <cstring>
#include <mutex>
#include <thread>

const char* GetFolderPath() {
    static std::vector<std::string> paths = {"this is a path", "here is another one",
                                             "what do we have here", "mother of dirs",
                                             "what did the tomatoe ..."};
    static size_t idx = 0;
    static char buf[256];
    std::strcpy(buf, paths[idx].c_str());
    idx = (idx + 1) % paths.size();
    return buf;
}

class DtIndexer {
    std::mutex mtx_cout; // std::cout mutex

public:
    void ThreadedIndex(std::string folderPath) {
        std::lock_guard lock(mtx_cout); // wait until this thread acquires the mutex
        std::cout << "\t-> Indexing Folder: " << folderPath << "\n";
    }

    void UpdateIndex() {
        std::vector<std::thread> threadList;

        { // lock_guard scope
            std::lock_guard lock(mtx_cout); // acquire mutex

            for(int i = 0; i < 50; ++i) {
                // const char* folder = GetFolderPath();
                std::string folder(GetFolderPath());

                std::cout << "\t-> Adding Folder to Thread: " << folder << "\n";

                //             safe copy here --+       +--- thread runs here ---+
                //                              |       |                        |
                //                              V       V                        V
                threadList.emplace_back( [this, folder] { ThreadedIndex(folder); });
                //                      Δ
                //                      |
                //                      +-- no std::thread(... needed here
            }
        } // lock_guard releases mutex here

        for(auto& t : threadList) t.join();
    }
};

int main() {
    DtIndexer a;
    a.UpdateIndex();
}

您可以将上面的 folder 字符串替换为 const char* 并查看您遇到的相同问题。