为什么只有最后一个线程执

时间:2015-06-26 11:13:43

标签: c++ multithreading boost visual-studio-2013

我需要创建计算文件夹中文件的控制台应用程序。每个文件夹执行并行。我从.txt文件获取目录路径并将它们放到线程中。

我使用std :: thread和boost :: filesystem。

它适用于一个目录,但崩溃或返回错误的结果很多。 有趣的是,最后一个线程总是得到正确的结果,但之前的那些是错误的。

这是我的代码:

DirHandler.h

#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <windows.h>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

class DirHandler{

public:
DirHandler();

void getPaths(ifstream file);
void output();
static void run_thread(pair<string, int> * dir, string cur_path, void *args)
{
    DirHandler *prunnable = static_cast<DirHandler*>(args);
    prunnable->some_counting(dir, cur_path);
}

private:

vector<thread> threads;
vector<pair<string, int>> paths; // current directory name and files amount

void some_counting(pair<string, int> * dir, string cur_path);
void escape();
};

DirHandler.cpp

void DirHandler::getPaths(ifstream file)
{
// parse pathes and create separate thread for each
string line;
if (file.is_open())
{
    while (getline(file, line))
    {
        cout << line << endl;
        // add thread for path
        pair<string, int> dir = make_pair(line, 0);
        paths.push_back(dir);
        threads.push_back(thread(&DirHandler::run_thread, &paths.back(), line, this));
    }
    for (auto& thr : threads){
        thr.join();
    }

    file.close();
}
}

void DirHandler::some_counting(pair<string, int> * dir, string cur_path){...}

的main.cpp

#include <iostream>
#include <windows.h>
#include "DirHandler.h"

int main(int argc, char* argv[])
{

    DirHandler dirHandler = DirHandler();
    dirHandler.getPaths(ifstream("strings.txt")); //ifstream(argv[1])

    dirHandler.output();



    return 0;
}

注意:调试时我发现最后的所有流最后都有id = 0

此外,我已经读过该问题可能是由对单个对象的引用引起的。 (就我而言,它是vector<pair<string, int>> paths

所以我的问题是如何让几个线程正常工作?

2 个答案:

答案 0 :(得分:2)

问题是你从paths向量得到指针,如果向量被调整大小,所有先前的指针(和迭代器)到向量中的元素都将变为无效。使用无效指针会导致undefined behavior,这通常会导致崩溃。

造成矢量的一种常见方法是向其中添加新元素,这正是您在循环中所做的。

一种解决方案是将对向量的引用和元素的索引传递给线程(索引在重新分配时不会更改)。另一个解决方案是有两个循环,一个用于将所有元素添加到向量中,第二个用于创建线程。

还有其他解决方案,例如不将指针传递给线程,而是通过值传递。这实际上是我推荐的解决方案。

稍微检查一下你的代码之后,我也看到了,因为你使用std::thread,根本不需要静态成员函数包装器。相反,您可以直接调用非静态实际线程函数:

threads.emplace_back(&DirHandler::some_counting, this, paths.back(), line);

[注意使用this作为第二个参数,以及emplace_back向量的更改threads

答案 1 :(得分:0)

嗯,最明显的问题是: socket.on('newdata', function(d){ var output = document.getElementById('output'); output.innerHTML = d; }) 你正在使用指向对象(threads.push_back(thread(&DirHandler::run_thread, &paths.back(), line, this));)的指针,它可能在&paths.back()之后不再存在。因此,应该修复此错误,您不能将指针传递给push_back项,除非您可以保证它不会重新分配其内部结构。

除了那些丑陋的代码,我什么也看不见。但vector方法可能潜伏着更多问题。