为什么我在 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 开始,通过复制捕获 this
和 folder
。您可能会注意到的另一件事是,当许多线程同时写入 std::cout
时,输出会出现乱码。您可以使用 std::mutex
和 std::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*
并查看您遇到的相同问题。
我很好奇我在这里做错了什么。我有以下功能:
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 开始,通过复制捕获 this
和 folder
。您可能会注意到的另一件事是,当许多线程同时写入 std::cout
时,输出会出现乱码。您可以使用 std::mutex
和 std::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*
并查看您遇到的相同问题。