虚拟Ubuntu64bit

时间:2016-10-22 19:54:59

标签: ubuntu

我正在尝试学习多线程和多进程编程。我对多线程/处理编程和Ubuntu环境都很陌生。我在下面的代码上工作了10个小时并修复了所有错误和警告。我开始使用xCode对其进行编码,它运行得很完美,并且正是我想要它做的,没有任何警告或错误。但是当尝试在Ubuntu上编译并运行时,我得到了一个分段错误(核心转储)我无法理解导致此错误的代码的哪一部分。关于哪个部分可能导致错误的任何想法?或者为什么我这样做?我记得Linux没有核心吗?非常感谢你!

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

int pid, i, rc, pid1, counter;
char* iterator[500];
char* file[500];
enum {

    WALK_OK = 0,
    WALK_BADPATTERN,
    WALK_BADOPEN,
};

int walker(const char *dir, const char *pattern)
{
    struct dirent *entry;
    regex_t reg;
    DIR *d;
    counter=0;
    if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB))
        return WALK_BADPATTERN;
    if (!(d = opendir(dir)))
        return WALK_BADOPEN;
    while ((entry = (readdir(d))) ){
        if (!regexec(&reg, entry->d_name, 0, NULL, 0)){
            puts(entry->d_name);
            file[counter]=entry->d_name;
            counter=counter+1;}
    }
    closedir(d);
    regfree(&reg);
    return counter;
}


void* project_statistics(int i){

    FILE* f;
 //   size_t len;
    char* line;
    int read[3];
    int arr[1000];
    int p, m, fnl;

    int counter2=0;
    f=fopen(iterator[i], "r");

    if (f==NULL) {
        err(1, "%s", iterator[i]);

    }
    while((line=fgets((char*)read,sizeof(read),f))){

        sscanf(line, "%d %d %d",&p, &m, &fnl);
        arr[counter2]= p;
        counter2++;
    }

    int *firstHalf = malloc((counter2) * sizeof(int));
    memcpy(firstHalf, arr, (counter2) * sizeof(int));

    //sort array;
    int k, l, tmp;

    for (k = 1; k < counter2; k++) {

        l = k;

        while (l > 0 && firstHalf[l - 1] > firstHalf[l]) {

            tmp = firstHalf[l];
            firstHalf[l] = firstHalf[l- 1];
            firstHalf[l- 1] = tmp;
            l--;

        }

    }

    printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]);

    if(!feof(f)){
        err(1, "getIn");
    }
    pthread_exit(NULL);

}

void* midterm_statistics(int i){

    FILE* f;
    int read[3];
    char* line;
    int arr2[1000];

    int p, m, fnl;

    int counter2=0;

    f=fopen(iterator[i], "r");

    if (f==NULL) {
        err(1, "%s", iterator[i]);

    }

    while((line=fgets((char*)read,sizeof(read),f))){

        sscanf(line, "%d %d %d",&p, &m, &fnl);
        arr2[counter2]=m;
        counter2++;
    }
    int *firstHalf = malloc((counter2) * sizeof(int));
    memcpy(firstHalf, arr2, (counter2) * sizeof(int));

    //sort array;
    int k, l, tmp;

    for (k = 1; k < counter2; k++) {

        l = k;

        while (l > 0 && firstHalf[l - 1] > firstHalf[l]) {

            tmp = firstHalf[l];
            firstHalf[l] = firstHalf[l- 1];
            firstHalf[l- 1] = tmp;
            l--;

        }

    }

    printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]);
    if(!feof(f)){
        err(1, "getIn");
    }
    pthread_exit(NULL);

}

void* final_statistics(int i){

    FILE* f;
    char* line;
    int arr3[1000];
    int read[3];
    int p, m, fnl;

    int counter2=0;

    f=fopen(iterator[i], "r");

    if (f==NULL) {
        err(1, "%s", iterator[i]);

    }

    while((line=fgets((char*)read,sizeof(read),f))){

        sscanf(line, "%d %d %d",&p, &m, &fnl);
        arr3[counter2]=fnl;
        counter2++;
    }

    int *firstHalf = malloc((counter2) * sizeof(int));
    memcpy(firstHalf, arr3, (counter2) * sizeof(int));

    //sort array;
    int k, l, tmp;

    for (k = 1; k < counter2; k++) {

        l = k;

        while (l > 0 && firstHalf[l - 1] > firstHalf[l]) {

            tmp = firstHalf[l];
            firstHalf[l] = firstHalf[l- 1];
            firstHalf[l- 1] = tmp;
            l--;

        }

    }

    printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]);

    if(!feof(f)){
        err(1, "getIn");
    }
    pthread_exit(NULL);

}



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

    char k[500];

    int counter1=walker("/home/ey/Desktop/sampleFolder/", ".\\.txt");
    for (i=0; i<counter1; i++) {
        strcpy(k, "/home/ey/Desktop/sampleFolder/");
        strcat(k, file[i]);
        iterator[i]=strdup(k);
        printf("%s",iterator[i]);
    }

    printf("\nMaster is starting\n");

    pthread_t tid1[counter1], tid2[counter1], tid3[counter1];
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    printf("\nslave1 start\n");
    printf("\n~Project Statistics~\n");

    sleep(2);
    for (i=0; i<counter1; i++) {

        rc=pthread_create(&tid1[i], &attr, (void*)*project_statistics,(void*)(intptr_t)i);

    }

    sleep(2);

    printf("\nslave1 done\n");


    printf("\nslave2 start\n");
    printf("\n~Midterm Statistics~\n");

    pid=fork();
    sleep(2);
    if (pid==0) {
        for (i=0; i<counter1; i++) {

            rc=pthread_create(&tid2[i], &attr,(void*)*midterm_statistics, (void*)(intptr_t)i);
        }

        sleep(2);
        printf("\nslave2 done\n");
        printf("\nslave3 start\n");
        printf("\n~Final Statistics~\n");
    }
    sleep(2);

    pid1=fork();
    sleep(2);

    if ((pid1==0)&&(pid==0)) {

        for (i=0; i<counter1; i++) {

            rc=pthread_create(&tid3[i], &attr, (void*)*final_statistics, (void*)(intptr_t)i);
        }

        sleep(2);
        printf("\nslave3 done\n");
        printf("\nMaster is done\n");
    }




    sleep(1);
    pthread_attr_destroy(&attr);
    pthread_exit(NULL);

}

1 个答案:

答案 0 :(得分:1)

main中,您的strcat发生了错误。

源地址为file[i]filechar *指针的全局数组。但是,它[显然]从未初始化为任何东西。

因此strcat调用将有NULL的第二个参数,这会导致段错误。

如果walker返回非零值,则可能会发生这种情况,如果目录不存在(即返回为WALK_BADOPEN),则会发生这种情况。这可以解释为什么它在一个系统上工作而在另一个系统上工作(即目录存在于一个系统而不存在于另一个系统上)。

因此,walker正在使用返回错误代码,但main正在使用此返回值作为计数。这个逻辑不正确。我相信您需要更改walker的返回值或让main以不同的方式获取计数。

解决此问题的简单方法是使错误代码为负值,并main进行检查。然后,walker可以正确返回计数。

因此,如果目录不存在,则返回值为2. main中的循环将在file[0]上出错,因为file中的任何内容都未设置为任何内容。

<强>更新

  

但是这次因为我知道目录确实存在,我可以尝试以错误的方式打开它吗?

没有&#34;错误&#34;使用opendir的方式 - 它已打开或失败,您已经处理过。

但是,在walker内,您不能依赖循环迭代到迭代的d_name值,因此,您必须使用strdup

变化:

file[counter] = entry->d_name;

分为:

file[counter] = strdup(entry->d_name);

此外,您应该限制检查file的最大值(例如,目前只有500)

更新#2:

在你的线程函数中,由于libc的fgets函数,你正在read进入read [而不是这是一个不错的选择]。但是,它是:

int read[3];

因此,行缓冲区 12个字节长。这可能会导致fgets读取一行两个部分拆分行。此可能导致arr数组溢出

我将其更改为:

char buf[1000];

我将线程函数的复制代码组合到一个公共代码中。

请注意firstHalf已分配,但从未释放。所以,这是&#34;泄漏&#34;。我为它添加了free电话。

另请注意,没有fclose(f)可能会导致fopen返回NULL(即段错误的其他来源)。

我还重做了线程连接和fork逻辑,并添加了waitpid。另请注意在fork的子代码中添加exit(0)

当我试图理解事物时,我正在简化事情,所以以下是一个公平的返工,可能看起来有点&#34;外星人&#34;起初[请原谅无偿的风格清理]:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <regex.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>

#if 1
#define MYDIR   "/home/ey/Desktop/sampleFolder/"
#else
#define MYDIR   "/tmp/data/"
#endif

#define dbgprt(_fmt...) \
    do { \
        if (opt_dbg) \
            printf(_fmt); \
    } while (0)

int opt_dbg;

int pid;
int i;
int rc;
int pid1;
int counter;

char *iterator[500];
char *file[500];

enum {
    WALK_OK = 0,
    WALK_BADPATTERN = -1,
    WALK_BADOPEN = -2,
};

int
walker(const char *dir,const char *pattern)
{
    struct dirent *entry;
    regex_t reg;
    DIR *d;

    counter = 0;
    if (regcomp(&reg,pattern,REG_EXTENDED | REG_NOSUB))
        return WALK_BADPATTERN;

    d = opendir(dir);
    if (d == NULL)
        return WALK_BADOPEN;

    while (1) {
        entry = readdir(d);
        if (entry == NULL)
            break;

        if (!regexec(&reg,entry->d_name,0,NULL,0)) {
            puts(entry->d_name);
            file[counter] = strdup(entry->d_name);
            counter = counter + 1;
        }
    }

    closedir(d);
    regfree(&reg);
    return counter;
}

void *
thread_common(void *arg,int column)
{
    intptr_t i = (intptr_t) arg;
    FILE *f;

    // size_t len;
    char *line;
    int data[3];
    char buf[1000];
    int arr[1000];

    int counter2 = 0;

    f = fopen(iterator[i],"r");
    if (f == NULL) {
        err(1,"%s",iterator[i]);
    }

    dbgprt("DEBUG reading ...\n");
    while (1) {
        line = fgets(buf,sizeof(buf),f);
        if (line == NULL)
            break;

        sscanf(line,"%d %d %d",&data[0],&data[1],&data[2]);
        arr[counter2] = data[column];

        counter2++;
        dbgprt("DEBUG line %d %s\n",counter2,iterator[i]);
        if (counter2 >= 1000) {
            printf("overflow %s\n",iterator[i]);
            exit(1);
        }
    }

    if (!feof(f)) {
        err(1,"getIn");
    }

    fclose(f);

    int *firstHalf = malloc((counter2) * sizeof(int));
    memcpy(firstHalf,arr,(counter2) * sizeof(int));

    // sort array;
    int k,
     l,
     tmp;

    dbgprt("DEBUG sorting ...\n");
    for (k = 1; k < counter2; k++) {
        for (l = k;  (l > 0) && (firstHalf[l - 1] > firstHalf[l]);  l--) {
            tmp = firstHalf[l];
            firstHalf[l] = firstHalf[l - 1];
            firstHalf[l - 1] = tmp;
            l--;
        }
    }

    printf("course %ld project median: %d, project min: %d, project max: %d\n",
        i + 1,firstHalf[counter2 / 2],firstHalf[0],firstHalf[counter2 - 1]);

    free(firstHalf);

    return (void *) 0;
}

void *
project_statistics(void *arg)
{

    return thread_common(arg,0);
}

void *
midterm_statistics(void *arg)
{

    return thread_common(arg,1);
}

void *
final_statistics(void *arg)
{

    return thread_common(arg,2);
}

int
main(int argc,char **argv)
{
    intptr_t i;
    char *cp;
    char krkt[500];

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'd':
            opt_dbg = 1;
            break;

        default:
            break;
        }
    }

    int counter1 = walker(MYDIR,".\\.txt");
    dbgprt("main: walker returned %d\n",counter1);
    if (counter1 <= 0)
        exit(1);

    for (i = 0; i < counter1; i++) {
        strcpy(krkt,MYDIR);
        if (file[i] == NULL)
            exit(3);
        strcat(krkt,file[i]);
        iterator[i] = strdup(krkt);
        printf("%s\n",iterator[i]);
    }

    printf("\nMaster is starting\n");

    pthread_t tid1[counter1];
    pthread_t tid2[counter1];
    pthread_t tid3[counter1];
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
    printf("\nslave1 start\n");
    printf("\n~Project Statistics~\n");

    //sleep(2);
    for (i = 0; i < counter1; i++)
        rc = pthread_create(&tid1[i],&attr,project_statistics,(void *) i);

    for (i = 0; i < counter1; i++)
        rc = pthread_join(tid1[i],NULL);
    printf("\nslave1 done\n");

    pid = fork();
    if (pid == 0) {
        printf("\nslave2 start\n");
        printf("\n~Midterm Statistics~\n");

        for (i = 0; i < counter1; i++)
            rc = pthread_create(&tid2[i],&attr,midterm_statistics,(void *) i);

        for (i = 0; i < counter1; i++)
            rc = pthread_join(tid2[i],NULL);

        printf("\nslave2 done\n");
        exit(0);
    }

    pid1 = fork();
    if (pid1 == 0) {
        printf("\nslave3 start\n");
        printf("\n~Final Statistics~\n");

        for (i = 0; i < counter1; i++)
            rc = pthread_create(&tid3[i],&attr,final_statistics,(void *) i);

        for (i = 0; i < counter1; i++)
            rc = pthread_join(tid3[i],NULL);

        printf("\nslave3 done\n");
        exit(0);
    }

    waitpid(pid,NULL,0);
    waitpid(pid1,NULL,0);
    printf("\nMaster is done\n");

    pthread_attr_destroy(&attr);

    return 0;
}

更新#3:

  

主要的开头对我来说也不是那么清楚,为什么我们要等待一个&#39; d&#39;并制作一个switch-case,为什么需要在代码中添加argv和argc?由于代码在某种程度上依赖于argv和argc,我的编译方式是否会导致问题?

argc/argv代码只解析选项参数。这是非常标准的样板。

在这种情况下,如果您执行./main -d,则会设置opt_d。然后,dbgprt宏对此进行测试,如果设置,则执行printf。因此,与调试输出相关的所有printf都更改为dbgprt

这样做改变程序的执行,只需添加额外的调试输出。如果您愿意,可以添加更多dbgprt

并且,您可以通过将它们添加到switch/case来添加自己的命令行选项。

这种技术用于&#34; printf调试&#34;很常见我更喜欢在可能的情况下使用gdb。就个人而言,我尝试使用gdb来调用该程序,只有当我有一个&#34;严重的&#34;错误,例如段错误。 gdb我可以识别断层线。然后,我添加assert,调试打印等内容,以预先缓解问题。

  

我有点理解逻辑,但我无法运行代码。我的意思是它仍在使用xcode。

我修复的错误也适用于xcode版本。

  

但是在Linux中它没有给出任何错误或警告,但是当键入./main时我什么都没得到......

如果您在Linux上运行,请使用-d。然后,在调用dbgprt之后,请注意第一个walker的输出。

我最好的猜测是walker返回一个负值(即目录不存在 - 模式没问题,因此剩下的是什么)。或者,返回0表示目录没有文件,或者没有与模式匹配的文件。

该程序应以exit(1)结束,因此请检查错误代码(例如echo $?

可以 [并且在考虑之后,可能应该]将第一个dbgprt更改回printf,因此它始终打印即使你没有指定-d,也是如此。这样,你就不会得到#34;沉默&#34;失败,但程序会事先告诉你,如果有什么不妥。

帮助调试此的一种方法是以使用gdb。做gdb ./main。然后,执行b walkerwalker上设置断点,然后键入rungdb将在walker的第一个语句处停止该程序。

然后,您可以将s键入&#34;单步&#34;该程序。你可以继续重复这个。当您有提示时,您可以使用gdb的p命令来打印变量。这样您就可以了解walker的作用。

当一行调用libc函数时,例如opendirreaddirstrdup等,执行s会尝试单步这些功能。冗长,并没有那么有用。因此,在这样一行上,请改用n。如果您误操作s,则可以输入finish

如果您认为自己已经走得够多,可以输入c,这将继续全速执行程序。

gdb有很多命令,上面只是几个。它具有内联帮助,因此请在提示符下键入help。或者,help b等。有许多教程可用。

相关问题