【问题标题】:Segmentation Fault when using Structures and pThreads使用结构和 pThread 时出现分段错误
【发布时间】:2016-06-28 19:50:54
【问题描述】:

我一直在使用一个程序,该程序将读取多个文本文件,记录其中的单词数,并将所有单词及其频率写入文件。但是,我在代码中的某处遇到了分段错误。我曾尝试使用 Valgrind 等工具来帮助我调试它,但它只指向我在主循环中所说的 int i = 0 的位置。对于发布我的大部分代码,我深表歉意,但我花了几个小时试图找到错误所在,并且似乎无法在我的一生中找到它。当我开始在 pthread_exit() 中传递一个结构时,问题就开始了。

#include <iostream>
#include <fstream>
#include <string>
#include <pthread.h>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>
using namespace std;

// Create a structure that we can store information in
typedef struct info{
    int words;
    string dictionary[500000];
} info;

// Counts the number of words in the text file so we know how big to make our array
int countWord(char *arg){
    char words[25000];
    int count = 0;

    ifstream check;
    check.open(arg);
    while(!check.eof()){
        check>>words;
        count++;
    }
    cout<<"Word Count: "<< count << '\n';
    check.close();
    return count;

}

// Checks to see if the word exists in our dictionary or not
int findWord(string array[], string target, int wordCount){
    for(int i = 0; i < wordCount; ++i){
        if(array[i] == target){
            return 1;
        }
    }
    return 0;
}


// Checks to see how many times a word is repeated
int checkWord(string array[], string target, int wordCount){
    int number = 0;
    for(int i = 0; i < wordCount; i++){
        if(array[i] == target){
            number++;
        }
    }
    return number;
}


void *threads(void *arg){
    info information;
    char *fileName = (char *)arg;
    ifstream myfile (fileName);
    string line;
    string fullText[15000];
    string dictionary[500000];
    int wordCount = countWord(fileName);
    int i = 0;
    int find;
    int check;
    int x = 0;
    int checkingStart = 0;


    // Opens and reads the file word by word removing any symbols that we dislike
    if (myfile.is_open()){
        while(myfile >> line){
            transform(line.begin(), line.end(), line.begin(), ::tolower);
            line.erase(remove(line.begin(), line.end(), ','), line.end());
            fullText[i] = line;
            i++;
        }
    }

    else cout << "Unable to Open the File";
    myfile.close();

    // Goes through and adds all the words to our dictionary
    for(i = 0; i < wordCount; ++i){
        find = findWord(dictionary, fullText[i], wordCount);
        if(find == 0){
            dictionary[x] = {fullText[i]};
            ++x;
            checkingStart = 1;
        }
    }

    // Sets each section of dictionary equal to the one in the structure
    for(i = 0; i < wordCount; ++i){
        information.dictionary[i] = dictionary[i];
    }

    // Sets words equal to word count and then passes the structure information out of the thread
    information.words = wordCount;
    pthread_exit(&information);
    return NULL;
}

int main(){
    int i = 0;
    int x = 0;
    int y = 0;
    int z = 0;
    int a = 0;
    int b = 0;
    int add = 0;
    int currentSize = 0;
    int checkingStart = 0;
    int wordCount;
    int find;
    string fullDictionary[500000];
    string dict[500000];
    ofstream writeFile;
    info information;
    char *fileName;
    char *fileList[2];
    pthread_t threadCount[2];
    int frequency[500000];
    int check;
    fileList[0] = "text1";
    fileList[1] = "text2";

    // Creates a loop that creates and joins threads for each text file
    for(a = 0; a < 1; ++a){
        fileName = fileList[a];
        pthread_create(&threadCount[a], NULL, threads, &fileName);
        pthread_join(threadCount[a], (void **)&information);
        wordCount = information.words;

        // Sets each part of dict equal to the same slot on info.dict
        for(b = 0; b < wordCount; ++b){
            dict[b] = information.dictionary[b];
        }

        // Adds to a complete list of all the text files added together
        for(y = 0, z = currentSize; z < wordCount; ++z, ++y){
            fullDictionary[z] = dict[y];
        }
        currentSize = (currentSize + wordCount);
    }

    // Goes through and adds all the words to our dictionary
        for(i = 0; i < wordCount; ++i){
            find = findWord(dict, fullDictionary[i], currentSize);
            if(find == 0){
                dict[x] = {fullDictionary[i]};
                cout << "Added the Word: " << fullDictionary[i] << "\n";
                add = 1;
                checkingStart = 1;
            }
            // Checks the number of times each word appears in the text file
            if(checkingStart == 1){
                    check = checkWord(fullDictionary, dict[x], wordCount);
                    frequency[x] = {check};

                }
            // Checks to see if it needs to move to the next open dictionary spot
            if(add == 1){
            ++x;
            add = 0;
                }
        }
return 0;
  }

【问题讨论】:

  • 如果你在调试器下运行你的程序,它应该会准确地告诉你发生分段错误的位置。然后,您可以检查发生故障时的变量值以了解发生了什么。
  • 你为什么不简单地使用std::vector&lt;std::string&gt; 而不是用string dictionary[500000]; 之类的东西来耗尽你的堆栈空间?你甚至在你的代码中有#include &lt;vector&gt;,但你没有使用它。
  • 可能是因为你在线程中返回“信息信息”是一个局部变量可能导致它。尝试分配结构并返回地址。
  • 离题:看看std::map<std::string, int>。您也许可以将大量代码减少到dictionarymap[word]++;

标签: c++ arrays string memory-leaks segmentation-fault


【解决方案1】:

这些是使程序运行所需的更改。

1) 一个问题似乎是函数线程中变量的大小。看起来每个生成的线程都有一些默认限制。您可以阅读 pthread_attr_setstacksize。但最简单的解决方案是减少线程中字符串的大小。因此,变量的大小就是为什么一旦调用线程函数就会给出分段错误。 正如上面 cmets 中已经提到的,使用矢量/地图类将有助于减少对大型局部变量的需求。

2) 返回变量必须是非局部变量,否则返回值不能成功返回。

3) 刚刚注意到主循环(变量 a )只运行一次。同样,一旦线程启动(pthread_create),循环就会等待 join 。这将导致线程的序列化。可以先创建,然后可以在单独的循环中调用连接。

变化如下..

在函数中 - 线程

  info *information;  
  //changed to pointer
  // info information;                                                                                                                                                                                         
  char *fileName = (char *)arg;                                                                      
  ifstream myfile (fileName);                                                                        
  string line;                                                                                       
  string fullText[1500];                                                                                                                                                                                      
  string dictionary[5000];  
  // reduced size                                                                                                                                                                                   
  //string fullText[15000]; 
  //string dictionary[500000];   

.....

 information = new info;    // create an instance 

........

// change to pointer 
     information->dictionary[i] = dictionary[i];                                                                                                                                                              
  }                                                                                                  

  // Sets words equal to word count and then passes the structure information out of the thread      
  information->words = wordCount;                                                                                                                                                                             
  pthread_exit(information); // return pointer 

在函数中 - 主要

info *information; // change to pointer 

....

 for(a = 0; a < 2; ++a){      // loop to 2 

.....

pthread_create(&threadCount[a], NULL, threads, (void *)fileName);  // changed file name                               
// pthread_create(&threadCount[a], NULL, threads, &fileName);   



wordCount = information->words; // changed for pointer 
...

dict[b] = information->dictionary[b]  // changed for pointer      

编辑完成后,您应该能够运行以调试其余功能。

【讨论】:

  • 非常感谢您帮助我编写代码,但是如果我使用诸如 valgrind 之类的调试器,它总是会在我之前所说的相同位置显示“无效写入大小 4” - int我 = 0;在主循环中。有什么想法吗?
  • 猜你有类似的问题,这次是在 main() 中,因为你的 main() 中有太多巨大的变量作为局部变量。可能它们会导致您的 stack 出现问题,您可以将它们移动到全局空间(在 main 之外)或减小它们的大小。更好的选择是将变量(如上面 cmets 中的建议)转换为矢量/地图等。如果这不能解决您的问题,您需要提供最新的代码和完整的错误。
猜你喜欢
  • 2020-08-04
  • 2018-10-03
  • 2020-08-02
  • 2015-06-06
  • 1970-01-01
  • 2021-11-08
  • 2014-05-31
  • 2011-03-23
相关资源
最近更新 更多