【问题标题】:C++ 11 thread class member function in for loop gives segmentation faultfor循环中的C ++ 11线程类成员函数给出分段错误
【发布时间】:2017-10-17 13:46:25
【问题描述】:

我有 8 个数据集作为对存储在一个向量中,并决定一个一个地传递到一个类中,并使用该类中的一个函数做一些工作。产生分段错误。这是我的代码:

vector<thread> threads;
for (int i = 0; i < 8; i++) { // generate 8 threads
    LogOdd CEB; // create LogOdd obj
    CEB.set_data(coord[i].second, coord[i].first); // pass parameters to private members
    threads.push_back(thread(&LogOdd::scan, &CEB));
for (int i = 0; i < 8; i++){    
    threads[i].join();
}

类看起来像:

class LogOdd {
private:
    string sequence;
    string chromosome;
public:
    void scan() { // function to be threaded
    ...
    }
    void set_data(string SEQUENCE, string CHROMOSOME) { // set parameters
        sequence = SEQUENCE;
        chromosome = CHROMOSOME;
    }
};

我很确定在第一个线程 for 循环中生成的分段错误,但不知道......我知道这个主题可能是重复的,但我已经做了很多搜索。请帮忙!

更新 谢谢回答我的问题。我以 2 种方式编辑了我的代码,它们都可以工作!

vector<thread> threads;
for (int i = 0; i < 8; i++) { // generate 8 threads
    LogOdd * CEB = new LogOdd; // create LogOdd obj
    CEB->sequence = coord[i].second;
    CEB->chromosome = coord[i].first;
    threads.push_back(thread(&LogOdd::scan, CEB));
}

我做的另一种方法是先将所有 8 个 obj 存储到一个向量中,然后分配给线程:

vector<thread> threads;
vector<LogOdd> LogOddvec;
for (int i = 0; i < 8; i++) {
    LogOdd CEB;
    CEB.sequence = coord[i].second;
    CEB.chromosome = coord[i].first;
    LogOddvec.push_back(CEB);
}
for (int i = 0; i < 8; i++) {
    threads.push_back(thread(&LogOdd::scandinuc, &LogOddvec[i]));
}

【问题讨论】:

  • 想想这个对象的生命周期是多少:LogOdd CEB;

标签: c++ multithreading class segmentation-fault


【解决方案1】:

让我们看看这些行:

for (int i = 0; i < 8; i++) { // generate 8 threads
    LogOdd CEB; // create LogOdd obj
    ...
    threads.push_back(thread(&LogOdd::scan, &CEB));
    ...
}

在循环内定义变量CEB。您将指向此变量的指针传递给线程。然后循环迭代,CEB 超出范围并被破坏

这意味着线程被传递了一个指向被破坏对象的指针。在线程中取消引用该指针将导致 undefined behavior 这是像您这样的崩溃的非常常见的原因。

最简单的解决方案是使用new 动态分配LogOdd 对象。一个可能更好的解决方案是将 CEB 按值传递给线程函数。另一种解决方案是将coord[i].secondcoord[i].first 作为参数传递给线程函数(或者可能是对coord[i] 的常量引用),并让线程函数创建自己的LogOdd 对象。

【讨论】:

  • 或者组合你的解决方案并通过值传递一个智能指针——那么它就不需要复制操作符
  • 如果 LogOdd 是可移动的并且移动很便宜,您实际上可以省略任何动态内存分配并调用 thread([ceb = std::move(CEB)] mutable { ceb.scan(); })
  • 感谢您回答我的问题! @Some程序员老兄虽然你已经清楚地说明了第三种解决方案,但我想问一下如何“让线程函数创建自己的LogOdd对象”......
  • @Fei-manHsu 只需将coord[i] 作为参数传递给线程函数(它是std::pair 吗?)。并在线程函数中定义LogOdd CEB;,后跟例如CEB.set_data(coord.second, coord.first);.
【解决方案2】:

我相信问题出在LogOdd CEB。您将它静态分配在一个块内,因此它会在块结束时被销毁,也就是在创建它的迭代结束时。

然后,您正在使用一个指向不再存在的对象的指针,这最终成为未定义的行为。最简单的解决方案是使用new 动态分配它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 2015-09-10
    相关资源
    最近更新 更多