【问题标题】:C++ Getting "Debug Error R6010 -abort() has been called " when i assign promises to threads当我将承诺分配给线程时,C++ 得到“调试错误 R6010 -abort() 已被调用”
【发布时间】:2016-05-18 09:17:40
【问题描述】:

我收到错误消息:Debug Error R6010 -abort() has been called

在我的代码中:

bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;

directories.push(path);
files.clear();

while (!directories.empty()) {
    path = directories.top();
    spec = path + L"\\" + mask;
    directories.pop();

    hFind = FindFirstFile(spec.c_str(), &ffd);
    if (hFind == INVALID_HANDLE_VALUE)  {
        return false;
    }

    do {
        if (wcscmp(ffd.cFileName, L".") != 0 && wcscmp(ffd.cFileName, L"..") != 0) {
            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                directories.push(path + L"/" + ffd.cFileName);
            }
            else {
                files.push_back(path + L"/" + ffd.cFileName);
            }
        }
    } while (FindNextFile(hFind, &ffd) != 0);

    if (GetLastError() != ERROR_NO_MORE_FILES) {
        FindClose(hFind);
        return false;
    }

    FindClose(hFind);
    hFind = INVALID_HANDLE_VALUE;
}

return true;}

void findText(std::string filename, std::string word , promise<string> &prom) {
std::ifstream f(filename);
std::string s;
std::string notFound = "no";
bool found = false;
if (!f) {
    std::cout << "il file non esiste"<<std::endl;
}
while (f.good()) {
        std::getline(f, s);
        if (s.find(word, 0) != string::npos) {
            found = true;
        }

    }
if (found) {

    //cout << "Parola trovata in -> " << filename << endl;
    prom.set_value_at_thread_exit(filename);
}
else {
    prom.set_value_at_thread_exit(notFound);
}

f.close();}
int main(int argc, char* argv[]){
//vector<std::thread> th;
vector<future<string>> futures;
vector<wstring> files;
string search = "ciao";
string notFound = "no";
if (ListFiles(L"pds", L"*", files)) {

    for (vector<wstring>::iterator it = files.begin(); it != files.end(); ++it) {
        //wcout << it->c_str() << endl;
        wstring ws(it->c_str());
        string str(ws.begin(), ws.end());
        // Show String
        //cout << str << endl;
        //Creo una promise per ogni thread in cui andrò a cercare il risulato
        std::promise<string> prom;
        futures.push_back(prom.get_future());
        std::thread(findText,str,search,std::ref(prom)).detach();

    }
}   

for (int i = 0; i < futures.size(); i++){
    futures.at(i).wait();
    if (futures.at(i).get().compare(notFound)!=0)
    cout << "Parola trovata in ->" <<futures.at(i).get()<<endl;
}
return 0;}

我之前尝试过不使用 Promise 并让每个线程在找到 word 并且它工作时打印文件名。 所以我不知道为什么使用承诺和未来来检索这个值会导致我这个问题...... 我正在使用 VS 2013

【问题讨论】:

  • 您是否尝试在调试器中运行以准确定位代码中发生的位置?你能至少指出代码中你显示它发生的地方吗,例如用注释(英文)?
  • 使用调试我收到这 2 个错误:std_Thread.exe 中 0x7545C41F 处的未处理异常:Microsoft C++ 异常:内存位置 0x003AF700 处的 std::future_error。运行-时间检查失败#0 - ESP 的值未在函数调用中正确保存。这通常是调用使用一种调用约定声明的函数和使用不同调用约定声明的函数指针的结果。 当我创建承诺并将其分配给线程时,问题必须出在主函数中。
  • 如果你在调试器中运行,程序会在你得到abort时停止。然后,您将能够将函数调用堆栈上移至您的代码,并确切地查看它在代码中发生的位置。
  • 我刚刚在最后一个 for 循环中添加了一个 try{} catch{} 块,它抛出异常:“broken promise”

标签: c++ multithreading promise future


【解决方案1】:

让我们仔细看看这些行:

for (...) {
    ...
    std::promise<string> prom;
    ...
    std::thread(findText,str,search,std::ref(prom)).detach();
}

首先创建一个局部变量prom,然后将对该变量的引用传递给线程。

这样做的问题是,一旦循环迭代,变量prom 就会超出范围并且对象被破坏。您曾经拥有的引用不再具有它引用的任何内容。使用引用会导致未定义的行为

所以解决方案是不使用引用(或指向prom 变量的指针),这会导致问题,因为std::promise 无法复制。但是,它可以移动:

std::thread(findText,str,search,std::move(prom)).detach();

为此,您可能需要让线程函数将 promise 参数作为右值引用:

void findText(std::string filename, std::string word , promise<string> &&prom) {
    ...
}

如果上述解决方案不起作用,那么您可以使用新的 C++11 智能指针(如 std::unique_ptr)使用动态分配。

那么线程函数应该按值获取智能指针,比如

void findText(std::string filename, std::string word , std::unique_ptr<std::promise<string>> prom) {
    ...
}

然后你像这样创建线程

auto prom = std::make_unique<std::promise<std::string>>();
// Or if you don't have std::make_unique
//   std::unique_ptr<std::promise<std::string>> prom(new std::promise<std::string>);
futures.push_back(prom->get_future();
std::thread(findText,str,search,std::move(prom)).detach();

请记住,在您的线程函数(findText)中,变量prom 是一个指针,在使用它时需要使用箭头运算符,例如

prom->set_value_at_thread_exit(filename);
//  ^^
// Note "arrow" operator here

【讨论】:

  • 那么如何解决这个问题并保持对承诺的跟踪?
  • 最后一行不是您问题的答案吗?
  • 修改这个我得到:...线程已经退出,代码为 3 (0x3)。
  • 使用你的答案 std::move(prom),我必须修改函数 findText 以 (promise prom) 而不是 (promise &prom) 但是我有这个错误 错误 2 错误 C2280: 'std::promise<:string>::promise(const std::promise<:string> &)' : 试图引用已删除的函数 c:\program files (x86 )\microsoft visual studio 12.0\vc\include\functional 1149 1 std_Thread
  • @A.Martino 更改线程函数以将承诺作为右值引用(即std::promise&lt;std::string&gt;&amp;&amp; prom)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-23
相关资源
最近更新 更多