【问题标题】:How do pthreads cause a segmentation fault in c (despite not allocating memory)?pthreads如何导致c中的分段错误(尽管没有分配内存)?
【发布时间】:2019-04-11 07:16:57
【问题描述】:

所以我试图递归地遍历某个给定的目录,并将每个子目录中每个文件的所有内容复制到一个输出文件中。我需要创建一个新线程来复制文件以及迭代任何子目录。我所做的是遍历终端给出的目录。每次调用 iterate_dir 时,都会创建一个 pthread 数组并为其创建一个计数器,因此我可以在加入所有创建的线程后关闭该目录。因此,如果找到一个子目录,我创建一个 pthread 来调用 iterate_dir 并将其传递一个新路径,将 pthread 数组增加一并将创建的 pthread 存储在其中。如果找到一个文件,我创建一个 pthread 来调用 copy_file,它打开文件读取其内容,将每个字符存储到一个共享字符串中(它是互斥的并且大小是动态的)。但是,我不断收到一些无法解释的分段错误。我输入了一个包含 2 个文件和 2 个子目录的目录,其中 1 个子目录为空,另一个包含 1 个文件。我尝试删除 copy_file 并使用它调用它的 pthread,但我仍然遇到段错误。我尝试删除我创建的 pthread 数组,但它仍然存在段错误。我尝试使用 gdb 逐步完成它,但没有确定的答案。我将提供两种情况,一种没有 copy_file 和 pthread 数组,一种有它们。他们都有段错误。我的问题是,即使没有分配任何东西,pthread 段错误如何(就像没有 copy_file 和 pthread 数组的代码一样)?我真的很困惑,想知道是否有人对任何其他代码有任何想法甚至建议。谢谢。

没有 pthread 数组和 copy_file(更容易阅读)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>

void* iterate_dir(void* args);


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

    char current_path[strlen(argv[1])+1];
    strcpy(current_path,argv[1]);


    pthread_t start;
    pthread_create(&start,NULL,&iterate_dir,current_path);
    pthread_join(start,NULL);

}



void* iterate_dir(void *args){


    DIR *dd = opendir((char*)args);
    struct dirent *curr;


    while((curr = readdir(dd))!=NULL){

        if(curr->d_type==DT_DIR && (strcmp(curr->d_name,".")==0 || strcmp(curr->d_name,"..")==0)){

            continue;

        }   

        if(curr->d_type==DT_DIR){


            char new_path[strlen(curr->d_name)+strlen((char*)args)+2];
            sprintf(new_path,"%s/%s",(char*)args,curr->d_name);
            pthread_t new_thread;
            pthread_create(&new_thread,NULL,&iterate_dir,new_path);


        }else{



        }


    }


    return NULL;

}

使用 copy_file 和 pthread 数组(更难阅读)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>

void* iterate_dir(void* args);
void* copy_file(void* args);

pthread_mutex_t mut_for_final_string;
pthread_mutex_t mut_for_current_string_position;
char* final_string;
int current_string_position;


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

    char current_path[strlen(argv[1])+1];
    strcpy(current_path,argv[1]);
    char new_file_path[strlen(argv[2])+15+1];
    sprintf(new_file_path,"%s/%s",argv[2],"AllFiles-sorted");
    int output = open(new_file_path, O_WRONLY|O_CREAT, 0666);

    final_string = (char*)malloc(sizeof(char));
    current_string_position = 0;

    pthread_mutex_init(&mut_for_final_string,NULL);
    pthread_mutex_init(&mut_for_current_string_position,NULL);

    pthread_t start;
    pthread_create(&start,NULL,&iterate_dir,current_path);
    pthread_join(start,NULL);

    write(output,final_string,current_string_position);

    pthread_mutex_destroy(&mut_for_final_string);
    pthread_mutex_destroy(&mut_for_current_string_position);

}


void* copy_file(void *args){

    int input = open((char*)args,O_RDONLY);
    char c;

    while(read(input,&c,1)>0){

        pthread_mutex_lock(&mut_for_final_string);
        pthread_mutex_lock(&mut_for_current_string_position);
        final_string[current_string_position] = c;
        char* tmp = NULL;
        tmp = realloc(final_string,(current_string_position)+2);
        while(tmp==NULL){}
        final_string = tmp;
        (current_string_position)++;
        pthread_mutex_unlock(&mut_for_current_string_position);
        pthread_mutex_unlock(&mut_for_final_string);

    }

    close(input);

    return NULL;

}


void* iterate_dir(void *args){


    DIR *dd = opendir((char*)args);
    struct dirent *curr;
    pthread_t* tids = (pthread_t*)malloc(sizeof(pthread_t));
    int tids_counter = 0;



    while((curr = readdir(dd))!=NULL){

        if(curr->d_type==DT_DIR && (strcmp(curr->d_name,".")==0 || strcmp(curr->d_name,"..")==0)){

            continue;

        }   

        if(curr->d_type==DT_DIR){


            char new_path[strlen(curr->d_name)+strlen((char*)args)+2];
            sprintf(new_path,"%s/%s",(char*)args,curr->d_name);
            pthread_t new_thread;
            pthread_create(&new_thread,NULL,&iterate_dir,new_path);
            tids[tids_counter] = new_thread;
            tids_counter++;

            pthread_t* tmp_ptr = NULL;
            tmp_ptr = realloc(tids, (sizeof(pthread_t)*(tids_counter+1)));
            while(tmp_ptr==NULL){}
            tids = tmp_ptr;


        }else{

            char old_path[strlen(curr->d_name)+strlen((char*)args)+2];
            sprintf(old_path,"%s/%s",(char*)args,curr->d_name);
            pthread_t new_thread;
            pthread_create(&new_thread,NULL,&copy_file,old_path);
            tids[tids_counter] = new_thread;
            tids_counter++;

            pthread_t* tmp_ptr = NULL;
            tmp_ptr = realloc(tids, (sizeof(pthread_t)*(tids_counter+1)));
            while(tmp_ptr==NULL){}
            tids = tmp_ptr;


        }


    }

    int i;
    for(i=0;i<tids_counter;i++){

        pthread_join(tids[i],NULL);

    }

    closedir(dd);

    return NULL;

}

【问题讨论】:

    标签: c segmentation-fault pthreads


    【解决方案1】:
    char new_path[strlen(curr->d_name)+strlen((char*)args)+2];
    

    一旦你离开它声明的范围,这个内存地址就无效了,但是你将该地址传递给一个新的 pthread。

    【讨论】:

    • 那我很困惑。我完全不使用 pthread 来运行代码(只是简单地调用 iterate_dir 而不是为其创建 pthread)并且它工作得很好。所以它在进行递归调用时在范围内,但在使用 pthread 进行调用时不在范围内?
    • @DevinM pthread_create“立即”返回,调用pthread_create的线程继续执行。 new_path 仅在调用线程停留在 if(curr-&gt;d_type==DT_DIR){ ... } 块中时才有效。如果您将pthread_create 替换为对iterate_dir 的调用,那么您只有一个执行线程并且调用线程在继续执行之前等待iterate_dir 返回,而它一直在if(curr-&gt;d_type==DT_DIR){ ... } 块中等待,所以new_path 仍在范围内。
    • “它工作得很好”,是的,因为你在执行时只有一个线程。 cleblanc 说你应该将内存地址传递给正在执行的线程。
    • 好的,我使用 malloc 来创建我传递的每个字符串,它似乎可以解决问题。感谢您的帮助和解释!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 2020-11-04
    • 2020-12-28
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    相关资源
    最近更新 更多