繁体   English   中英

程序中的分段错误错误,用于使用线程不计算文件中单词的出现次数

[英]Segmentation fault error in a program for counting no of occurences of a word in a file using threads

因此,我遇到以下问题:实现一个程序,该程序将文件名后跟单词作为参数。 为每个单词创建一个单独的线程以计算其在给定文件中的出现次数,并打印出所有单词的出现总数。

我的代码是:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>

pthread_mutex_t mtx; // used by each of the three threads to prevent  other threads from accessing global_sum during their additions

int global_sum = 0;
typedef struct{
                    char* word;
                    char* filename;
}MyStruct;



void *count(void*str)
{
    MyStruct *struc;
    struc = (MyStruct*)str; 
    const char *myfile = struc->filename;

    FILE *f;
    int count=0, j;
    char buf[50], read[100];
    // myfile[strlen(myfile)-1]='\0';
    if(!(f=fopen(myfile,"rt"))){
         printf("Wrong file name");
    }
    else
         printf("File opened successfully\n");
         for(j=0; fgets(read, 10, f)!=NULL; j++){
             if (strcmp(read[j],struc->word)==0)
                count++;
         }

    printf("the no of words is: %d \n",count);  
    pthread_mutex_lock(&mtx); // lock the mutex, to prevent other threads from accessing global_sum
    global_sum += count; // add thread's count result to global_sum
    pthread_mutex_unlock(&mtx); // unlock the mutex, to allow other threads to access the variable
}


int main(int argc, char* argv[]) {
    int i;
    MyStruct str; 

    pthread_mutex_init(&mtx, NULL); // initialize mutex
    pthread_t threads[argc-1]; // declare threads array 

    for (i=0;i<argc-2;i++){

       str.filename = argv[1];  
       str.word = argv[i+2];

       pthread_create(&threads[i], NULL, count, &str); 
    }

    for (i = 0; i < argc-1; ++i)
         pthread_join(threads[i], NULL);

    printf("The global sum is %d.\n", global_sum); // print global sum

    pthread_mutex_destroy(&mtx); // destroy the mutex

    return 0;

}

当我尝试运行它时,出现分段错误错误。 这是为什么? 谢谢!

main()两个i循环不同

for (i=0;i<argc-2;i++){
    ...
    pthread_create(&threads[i], NULL, count, &str); 
}

接着

for (i = 0; i < argc-1; ++i)
    pthread_join(threads[i], NULL);

在第二个循环中,您将引用在第一个循环中未创建的threads[argc-2]

首先,您的代码格式非常糟糕。 这甚至不一致。 您在启用警告的情况下进行编译也不会出现。

如果您是一门大学课程,并且他们没有告诉您如何格式化代码并通过警告进行编译,我强烈建议您请教您的导师提供什么。

如果使用gcc,请添加-Wall -Wextra。 对于编码风格,我建议从LinuxFreeBSD中窃取一种。 有多种编辑器可以为您设置代码格式,包括像vim这样的真正编辑器(即使看起来很苛刻也值得尝试)。

您的编码风格可帮助您解决问题。

void *count(void*str)
{
    MyStruct *struc;
    struc = (MyStruct*)str;
    const char *myfile = struc->filename;

    FILE *f;
    int count=0, j;
    char buf[50], read[100];

buf未使用,如果启用了警告,您将了解到。 读是一个坏名字。

    // myfile[strlen(myfile)-1]='\0';
    if(!(f=fopen(myfile,"rt"))){
         printf("Wrong file name");
    }
    else

因为您不返回(应有的状态),所以您将自己设置为执行代码的不正确行为,而不应该这样做。 不用猜测,您的“ else”子句是无效的。 您缺少花括号,因此即使文件打开操作失败,也会执行下面的for循环。

         printf("File opened successfully\n");
         for(j=0; fgets(read, 10, f)!=NULL; j++){

10点 好像是一个错字,您可能要输入100。如果使用sizeof,则不会发生这种情况。

             if (strcmp(read[j],struc->word)==0)
                count++;
         }

目前尚不清楚您在这里做什么。 似乎您想从read [0]开始,从read 1开始 ,等等进行strcmp。 但是,您读取了新数据并替换了原始缓冲区中的内容, 然后将其前进了一个。 这毫无意义。 最后,无论如何您做错了。 read [j]不会求值到一个地址,如果您要求,编译器会再次告诉您。

无论如何,strcmp方法非常糟糕。 尝试一种尝试匹配第一个字符并从那里开始工作的方法。

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

标准放错了“ *”。 使用char * argv []代替。

    int i;
    MyStruct str;

    pthread_mutex_init(&mtx, NULL); // initialize mutex
    pthread_t threads[argc-1]; // declare threads array

强烈不推荐。 首先验证参数,然后验证一个专用变量,该变量保存一定数量的线程。 此时,您可以分配一个数组。

    for (i=0;i<argc-2;i++){

       str.filename = argv[1];
       str.word = argv[i+2];

       pthread_create(&threads[i], NULL, count, &str);
    }

与线程类似,将路径保存在某处。 将其称为argv 1是不好的风格,这会再次咬住您。 对单词使用argv可以。

但是,这通常是错误的。 您设置了本地结构并将其传递给线程,然后立即对其进行更改 因此,发生在一天结束时,所有线程都在计数相同的单词。 但是他们所指的单词在此过程中发生了变化。

    for (i = 0; i < argc-1; ++i)
         pthread_join(threads[i], NULL);

去搞清楚。 您没有一个拥有一定数量线程的变量,这导致了这种不一致(argc-1 vs argc-2)。

通常,通过正确阅读编译器警告,可以在很大程度上解决此问题,并且如果采用基本的良好实践,通常可以避免此问题。

当然,无论如何都会发生错误,在这种情况下,您至少可以缩小范围。

最后,关于通用方法的几句话。 目前尚不清楚该练习的目的是什么。 实际上,您必须强迫自己使用除pthread_create和pthread_join之外的任何方法。 假设唯一的要求是使用线程。

我不知道他们是否强迫您多次打开文件。 多次打开和读取内容不仅浪费,而且在文件被替换并且某些线程打开另一个文件的情况下使您打开。

一个好的解决方案是在主目录中打开一次文件。 打开后,您可以将文件和fstat映射为大小。 如果由于某种原因不能使用mmap,则应分配足够大的缓冲区并读取文件。

然后,所有线程都可以获得该缓冲区的地址,要查找的单词以及它们应将计数器存储到的地址(每个线程获得一个不同的地址)。

当所有线程退出时,您将循环以求和。

无论哪种方式都不会涉及锁定。

一次(可能)读取(最多)10个字符将丢失某些正在搜索的单词实例。

strcmp()始终从10个字符的开头开始。

1)需要在文件中的任何位置查找目标词。

2)需要在读入缓冲区的任何位置查找目标单词。

建议:

0) clear input buffer
1) input one char at a time, 
accumulating characters in the input buffer,
2) when a word separator found, (for instance a space or EOF)
3) then check if the word matches the target word.  
4) if matches, increment count.   
5) if EOF, then exit, else goto 0 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM