【问题标题】:C++ Returning results from several threads into an arrayC ++将多个线程的结果返回到数组中
【发布时间】:2013-10-07 19:24:35
【问题描述】:

我有一个模式匹配程序,它将一个字符串作为输入并返回一个与字典非常匹配的字符串。由于该算法需要几秒钟来运行一个匹配查询,所以我尝试使用多线程来运行批处理查询。

我首先读入一个包含查询列表的文件,并为每个查询调度一个新线程来执行匹配算法,使用 pthread_join 将结果返回到一个数组中。

但是,我得到了一些不一致的结果。例如,如果我的查询文件包含术语“红、绿、蓝”,我可能会收到“红、绿、绿”作为结果。另一次运行可能会产生正确的“红、绿、蓝”结果。有时似乎会覆盖数组中的结果,但是为什么会发生这种情况,因为数组值是根据线程 id 设置的?

Dictionary dict;  // global, which performs the matching algorithm

void *match_worker(void *arg) {
    char* temp = (char *)arg;
    string strTemp(temp);
    string result = dict.match(strTemp);
    return (void *)(result.c_str());
}

void run(const string& queryFilename) {
    // read in query file
    vector<string> queries;
    ifstream inquery(queryFilename.c_str());
    string line;
    while (getline(inquery, line)) {
        queries.push_back(line);
    }
    inquery.close();

    pthread_t threads[queries.size()];
    void *results[queries.size()];
    int rc;
    size_t i;

    for (i = 0; i < queries.size(); i++) {
        rc = pthread_create(&threads[i], NULL, match_worker, (void *)(queries[i].c_str()));
        if (rc) {
            cout << "Failed pthread_create" << endl;
            exit(1);
        }
    }

    for (i = 0; i < queries.size(); i++) {
        rc = pthread_join(threads[i], &results[i]);
        if (rc) {
            cout << "Failed pthread_join" << endl;
            exit(1);
        }
    }

    for (i = 0; i < queries.size(); i++) {
        cout << (char *)results[i] << endl;
    }
}

int main(int argc, char* argv[]) {
    string queryFilename = arg[1];
    dict.init();
    run(queryFilename);
    return 0;
}

编辑:按照 Zac 的建议,我修改了线程以明确地将结果放在堆上:

void *match_worker(void *arg) {
    char* temp = (char *)arg;
    string strTemp(temp);
    int numResults = 1;
    cout << "perform match for " << strTemp << endl;
    string result = dict.match(strTemp, numResults);
    string* tmpResult = new string(result);
    return (void *)((*tmpResult).c_str());
}

虽然,在这种情况下,我会将删除调用放在哪里?如果我尝试将以下内容放在 run() 函数的末尾,则会出现无效指针错误。

for (i = 0; i < queries.size(); i++) {
    delete (char*)results[i];
}

【问题讨论】:

  • 字典是什么类型?它是线程安全的吗?听起来好像不是。

标签: c++ multithreading pthreads


【解决方案1】:

如果不调试,我的猜测是它与以下内容有关:

void *match_worker(void *arg) 
{
    char* temp = (char *)arg;
    string strTemp(temp);
    string result = dict.match(strTemp); // create an automatic
    return (void *)(result.c_str()); // return the automatic ... but it gets destructed right after this!
}

因此,当下一个线程运行时,它会写入您所指向的相同内存位置(偶然),并且您将两次插入相同的值(而不是写入它)。

您应该将结果放在堆上,以确保在线程退出和将其存储在主线程之间期间它不会被破坏。

在您的编辑中,您试图将事情混为一谈。我已经在下面修复了它:

void *match_worker(void *arg) 
{
    char* temp = (char *)arg;
    string strTemp(temp);
    int numResults = 1;
    cout << "perform match for " << strTemp << endl;
    string result = dict.match(strTemp, numResults);
    string* tmpResult = new string(result);
    return (void *)(tmpResult); // just return the pointer to the std::string object
}

声明results

// this shouldn't compile
//void* results[queries.size()]; 
std::string** results = new std::string[queries.size()];
for (int i = 0; i < queries.size(); ++i)
{
    results[i] = NULL; // initialize pointers in the array
}

当你清理内存时:

for (i = 0; i < queries.size(); i++) 
{
    delete results[i];
}
delete [] results; // delete the results array

也就是说,如果您使用 C++11 threading templates 而不是混合使用 C pthread 库和 C++,您会更轻松。

【讨论】:

  • @Aaron 已编辑以解决您的新问题。
【解决方案2】:

问题是由局部变量result的生命周期和成员函数result.c_str()返回的数据引起的。通过将 C 与 C++ 混合,您可以使这项任务变得不必要的困难。考虑使用 C++11 及其线程库。它使任务变得更加容易:

std::string match_worker(const std::string& query);

void run(const std::vector<std::string>& queries)
{
    std::vector<std::future<std::string>> results;
    results.reserve(queries.size());
    for (auto& query : queries)
        results.emplace_back(
            std::async(std::launch::async, match_worker, query));
    for (auto& result : results)
        std::cout << result.get() << '\n';
}

【讨论】:

    猜你喜欢
    • 2013-11-23
    • 2014-02-19
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2023-04-06
    • 2013-05-16
    • 1970-01-01
    • 2011-06-22
    相关资源
    最近更新 更多