2016-05-22 10 views
-1

Я должен написать бота, который читает веб-адреса из файла и выполняет запрос 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; 
} 

Ошибка я получаю:

* стек Smashing обнаружен *: ./bot прекращено грим: *** [Run] Отменено

Это происходит после завершения первой резьбы. Я знаю, что в памяти должна быть ошибка, но я не понимаю, почему я получаю эту ошибку. Я что-то упустил? Кроме того, любые другие советы могут быть исправлены!

+0

Как насчет использования wget? – nwp

+0

Зачем использовать указатели на связанные с потоком элементы структуры очереди? Почему бы просто не вставлять экземпляры этих типов непосредственно в структуру? Это, однако, просто источник утечки памяти; в коде есть другие. Но утечки памяти напрямую не являются причиной разрыва стека - проблемы несколько касаются вашей основной проблемы. –

+0

@nwp, потому что мы должны делать это так. Наш учитель дал нам класс для запроса GET, который он написал, и мы должны сортировать код вокруг него. –

ответ

1

Я уверен, что у вас есть ошибка в parseAddr:

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

Хотя args[0] и args[1] динамически выделяется, args сам не являюсь. Когда вы его вернете, на самом деле будет выделен указатель на args. Поскольку массив args уничтожается после выхода функции, попытка получить доступ к возвращенному значению приведет к неопределенному поведению.

Если вы хотите это сделать, передайте массив, который будет заполнен как один из аргументов функции, и получите функцию, чтобы заполнить ее вместо. Кроме того, можно динамически выделять массив (например, char** args; args = malloc(sizeof(char*)*2);

Если это не помогает, работает под valgrind может помочь придавить свою ошибку

+0

Теперь я получил следующее: 'char * args [2];
parseAddr (c, args);
' И в функции: ' char * next = strchr (c, '/'); printf ("<>>% s \ n", next); args [1] = malloc (sizeof (char) * MAXLINE); strcpy (args [1], next); next [0] = '\ 0'; args [0] = malloc (sizeof (char) * MAXLINE); strcpy (args [0], c); ' Еще одна ошибка, но спасибо за подсказку –

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); 

в противном случае, таНос выделить только один байт до того «STRLEN (новый) +1» байт передаются я в выделенную область.

Вы должны также рассмотреть этот вид предупреждения (уже упоминалось в другом ответе выше данного):

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

Давать краткое описание вашей среды также может помочь людям, чтобы решить вашу проблему.

+0

Первый совет не сделал трюк, но я вижу, что все равно должен его изменить. Посмотрите на это предупреждение в ближайшее время. Что вы подразумеваете под окружающей средой? –

+0

Окружающая среда = ваша платформа и компилятор/компоновщик. – jb07

+0

OS - это Linux Mint, я пишу в NetBeans/Notepaddqq и использую make-файл для его компиляции через терминал (gcc -o bot bot.c). Я могу опубликовать make-файл здесь, но я не думаю, что это связано с ошибкой, которую я получаю –