-1

ファイルからWebアドレスを読み取りGET、ファイルに再度書き込まれるリクエストを実行するボットを作成することになっています。これはこれまでのところ機能しますが、プログラムは常に「スタック破壊エラー」で終了します。私は複数の「コンシューマー」スレッドを使用して作業を行い、すべてのGETリクエストが完了して最初のスレッドが終了すると、プログラムは終了します。

以下は私のコードです:

#include <pthread.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "Socket/msocket.h"
/*
 * 
 */

#define MAXLINE 512

typedef struct {
    char** addr;
    long head, tail;
    int full, empty, reading;
    pthread_mutex_t *mut;
    pthread_cond_t *notFull, *notEmpty;
} queue;

typedef struct {
    struct queue *q;
    int tid;
} arguments;

int queueSize;
int elemCount=0;
int isEmpty;
char file[MAXLINE];

void *readFile(void *args);
void *consume(void *args);
char* parseLine(char*);
char** parseAddr(char*);
queue *queueInit (int);
void queueDelete (queue *q);
void queueAdd (queue *q, char* new);
void queueDel (queue *q, char** out, int *o);

/* main function
    argv[0]: program name (here ./bot)
    argv[1]: file name (xyz.txt,...)
    argv[2]: size of queue
    argv[3]: number of client/consumer threads
*/
int main(int argc, char** argv) {

    strcpy(file, argv[1]);
    queueSize = atoi(argv[2]);
    int maxCli = atoi(argv[3]);
    printf("-------queueSize: %i--------\n", queueSize);
    printf("---------maxCli: %i-------\n", maxCli);
    int j=0;
    queue *fifo;
    pthread_t prod, con[maxCli];
    struct timeval tv;

    fifo = queueInit(queueSize);
    if(fifo == NULL){
        printf("queueInit() failed");
        exit(1);
    }

    gettimeofday(&tv, NULL);
    double start = (tv.tv_sec) * 1000 + (tv.tv_usec)/1000;
    pthread_create(&prod, NULL, readFile, fifo);
    while(j<maxCli){

        arguments *threadSet = malloc(sizeof(arguments));
        threadSet->q = fifo;
        threadSet->tid = j+1;
        pthread_create(&con[j], NULL, consume, threadSet);
        j++;
    }
    j=0;
    pthread_join(prod, NULL);
    while(j<maxCli){
        pthread_join(con[j], NULL);
        j++;
    }
    double end = (tv.tv_sec) * 1000 + (tv.tv_usec)/1000;
    printf("time elapsed: %d\n", end-start);

    printf("----------------threads end----------------\n");
    queueDelete(fifo);

    return (EXIT_SUCCESS);
}

void *readFile(void *q){
    FILE *fp = fopen(file, "r");
    if(fp==NULL){
        printf("fopen() failed");
        return;
    }

    char tmp[MAXLINE];
    arguments *threadSet;
    queue *fifo;
    int k;

    fifo = (queue *)q;

    while(fgets(tmp, MAXLINE, fp) != NULL){
        pthread_mutex_lock(fifo->mut);
        if(fifo->full){
            printf("producer: queue FULL\n");
            pthread_cond_wait(fifo->notFull, fifo->mut);
        }
        strcpy(tmp, parseLine(tmp));
        queueAdd(fifo, tmp);
        elemCount++;
        printf("producer: added %s\n", tmp);
        printf("element count: %i\n", elemCount);

        pthread_mutex_unlock(fifo->mut);
        pthread_cond_signal(fifo->notEmpty);

        usleep(100000 + 100000);
    }
    fclose(fp);
    fifo->reading = 0;
    printf("--------------read end---------------\n");
    return(NULL);
}

void *consume(void *a){
    printf("consume begin\n");
    arguments *threadSet;
    queue *fifo;
    char* c;
    int elemNr;
    int retValue;

    threadSet = (arguments *)a;
    fifo = (queue *)threadSet->q;

    while(1){
        pthread_mutex_lock(fifo->mut);
        //printf("---------------consume begin--------------\n");
        if(fifo->empty && !fifo->reading){
            printf("end\n");
            break;
        }
        if(fifo->empty && fifo->reading){
            printf("consumer(%i): queue EMPTY\n", threadSet->tid);
            pthread_cond_wait(fifo->notEmpty, fifo->mut);
        }
        if(!fifo->empty){
            queueDel(fifo, &c, &elemNr);
            char fname_a[] = "file_";
            char* fname_b = malloc(MAXLINE);
            snprintf(fname_b, MAXLINE, "<%i>_<%i>.html", elemNr, threadSet->tid);
            strcat(fname_a, fname_b);
            printf("%s\n", fname_a);

            char** args;
            args = parseAddr(c);
            if( (retValue = askServer(args[0], args[1], fname_a)) < 0){
                printf("askServer() failed: %s\n", args[0]);
                printf("error value: %i\n", retValue);
                return(NULL);
            }
            elemCount--;
            printf("consumer(%i): picked %s\n", threadSet->tid, c);
            printf("---------------consume end--------------\n");
        }
        pthread_mutex_unlock(fifo->mut);
        pthread_cond_signal(fifo->notFull);
        usleep(200000 + 300000);
    }
    printf("end thread: consumer(%i)\n", threadSet->tid);
    free (threadSet);
    return(NULL);
}

char** parseAddr(char* c){
    char* args[2];

    char* next = strchr(c, '/');
    args[1] = malloc(sizeof(char)*MAXLINE);
    strcpy(args[1], next);

    next[0] = '\0';
    args[0] = malloc(sizeof(char)*MAXLINE);
    strcpy(args[0], c);

    return args;
}

char* parseLine(char* c){
    char* next = strchr(c, ' ');
    next[0] = '\0';

    char* t = next+1;
    next = strchr(t, '\n');
    if(next != NULL) next[0] = '\0';
    strcat(c, t);

    return c;
}

queue *queueInit (int size){
    queue *q;

    q = (queue *)malloc (sizeof (queue));
    if (q == NULL) return (NULL);

    q->addr = malloc(size);
    int i=0;
    while(i<size){
        q->addr[i] = malloc(sizeof(char)*MAXLINE);
        i++;
    }
    q->empty = 1;
    q->full = 0;
    q->reading = 1;
    q->head = 0;
    q->tail = 0;
    q->mut = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
    pthread_mutex_init (q->mut, NULL);
    q->notFull = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
    pthread_cond_init (q->notFull, NULL);
    q->notEmpty = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
    pthread_cond_init (q->notEmpty, NULL);

    return (q);
}

void queueDelete (queue *q){
    pthread_mutex_destroy (q->mut);
    free (q->mut);  
    pthread_cond_destroy (q->notFull);
    free (q->notFull);
    pthread_cond_destroy (q->notEmpty);
    free (q->notEmpty);

    int i=0;
    while(i<queueSize){
        free (q->addr[i]);
        i++;
    }
    free (q->addr);
    free (q);
}

void queueAdd (queue *q, char* new){
    q->addr[q->tail] = (char*)malloc(sizeof(char));
    strcpy(q->addr[q->tail], new);
    q->tail++;
    if (q->tail == queueSize)
        q->tail = 0;
    if (q->tail == q->head)
        q->full = 1;
    q->empty = 0;

    return;
}

void queueDel (queue *q, char **out, int *o){
    *out = q->addr[q->head];
    *o = q->head+1;

    q->head++;
    if (q->head == queueSize)
        q->head = 0;
    if (q->head == q->tail)
        q->empty = 1;
    q->full = 0;

    return;
 }

私が得ているエラー:

* スタック破壊が検出されました * : ./bot が終了しました make: *** [実行] 中止されました

これは、最初のスレッドが終了した後に発生します。メモリに間違いがあるに違いないことはわかっていますが、なぜこのエラーが発生するのかわかりません。ここで何か不足していますか?また、他のヒントも高く評価されています!

4

2 に答える 2

1

にバグがあると確信していますparseAddr

char** parseAddr(char* c){
    char* args[2];
    ...
    return args;
}

args[0]args[1]は動的に割り当てられますが、それargs自体はそうではありません。あなたがそれを返すとき、へのポインタargsが実際に割り当てられます。関数の終了後に配列が破棄されるためargs、戻り値にアクセスしようとすると、未定義の動作が発生します。

これを行う場合は、関数への引数の 1 つとして入力する配列を渡し、代わりに関数を取得して入力します。配列を動的に割り当てることもできます (例: char** args; args = malloc(sizeof(char*)*2);.

これで問題が解決しない場合は、以下で実行するとvalgrindエラーを突き止めるのに役立つ場合があります。

于 2016-05-22T12:07:45.330 に答える
0

おそらくここにも問題があります:

void queueAdd (queue *q, char* new){
    q->addr[q->tail] = (char*)malloc(sizeof(char));

次のように変更する必要があります。

void queueAdd (queue *q, char* new){
    q->addr[q->tail] = (char*)malloc(strlen(new)+1);

それ以外の場合、malloc は 'strlen(new)+1' バイトが割り当てられた領域に転送される前に 1 バイトだけを割り当てます。

この種の警告にも対処する必要があります(この上の別の回答ですでに言及されています):

thread.c: In function ‘parseAddr’:
thread.c:189:5: warning: function returns address of local variable [-Wreturn-local-addr]
     return args;
     ^

あなたの環境について簡単に説明することも、人々があなたの問題を解決するのに役立つかもしれません。

于 2016-05-22T12:41:35.833 に答える