Segmentation fault
От: alexora  
Дата: 01.06.04 22:00
Оценка:
Я вот написал софтину, которая чекает мыла на валидатность. Она у меня тредовая. Кол. тредов указываешь. Каждый тред считывает определенное кол. бай с файла и чекает мыла на MX записи. Чекаю я через
res_search
функцию. Тестирование я проводил при 500 тредах, каждый тред считывал по 10кб данных с файла. Прикол в том, что если закоментировать кусок кода, который чекает на MX записи, то все пашет (файл при єтом парсится тредами и переписывается в другой). Если оставить этот кусок кода, то на середине проверки вываливается Segmention fault Как это понять ?

Вот весь код :


#include <sys/types.h>
#include <stdio.h>
#include <pthread.h>
#include <g++/vector>
#include <g++/string>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <g++/iostream>
#include <sys/stat.h>
#include <unistd.h>
#include <g++/algorithm>


#define MAXTHREADCOUNT 500
#define MINTHREADCOUNT 1
#define STEPPOS           10240


void    readData(char*, long, int);
void    usage();
int     emailParse(char* email, string& account);
void*   thread_proc(void*);
long    getFileSize(char*);


struct threaddata
{
    long pos;
    int  id;
};

string  account = "                                      ";
long    threadcount = 0;
char    s_filein[128];
char    s_filebad[128];
char    s_filegood[128];
long    itemindex;
long    filesize = 0;
long    filepos  = 0;
pthread_t threads[MAXTHREADCOUNT];

threaddata MID[MAXTHREADCOUNT];
vector<string>  V[MAXTHREADCOUNT];
int        Free[MAXTHREADCOUNT];
vector<string>  whitelist;
vector<string>  badlist;

int main(int argc, char** argv)
{
    for (int index=1;index<argc;index++)
    {
            if (!strcmp("-threadcount",  argv[index])) threadcount = atoi(argv[index+1]); else
            if (!strcmp("-bad",          argv[index])) strcpy(s_filebad, argv[index+1]); else
            if (!strcmp("-in",           argv[index])) strcpy(s_filein,  argv[index+1]); else
            if (!strcmp("-good",         argv[index])) strcpy(s_filegood,argv[index+1]); 
    }

    if ((!threadcount) || (!strlen(s_filebad)) || (!strlen(s_filegood)) || (!strlen(s_filegood)))
    {
        usage();
        return 1;
    }

    if (!((threadcount<=MAXTHREADCOUNT) && (threadcount>=MINTHREADCOUNT))) 
    {
        usage();
        return 1;
    }

    filesize = getFileSize(s_filein);


    for (itemindex=0;itemindex<threadcount;itemindex++) Free[itemindex] = 1;    

    while (filepos<filesize)
    {
        for (itemindex=0;itemindex<threadcount;itemindex++)
        {
            if (Free[itemindex])
            {
                MID[itemindex].id  = itemindex;
                MID[itemindex].pos = filepos;
                pthread_create(&threads[itemindex], NULL, &thread_proc, &MID[itemindex]);
                filepos+=STEPPOS;
            }
        }
        sleep(1);
    }

        for (itemindex=0;itemindex<threadcount;itemindex++) pthread_join(threads[itemindex], NULL);

    return 0;
}

void usage()
{
    printf("Usage : \n");
    printf("$./a.out -in mails.txt -good good.txt -bad bad.txt -threadcount 50\n");
    printf("Note, please %i<=threadcount<=%i\n",MINTHREADCOUNT, MAXTHREADCOUNT);
}

void readData(char* filename, long p, int id)
{
    long    size = 0;
    char    ch = 0;
    char    line[100];
    FILE*   f = fopen(filename,"r");
    fseek(f, p, 0);
    if (p) while ((ch!='\n') && (!feof(f))) fscanf(f,"%c",&ch);

    V[id].clear();

    while ( (!feof(f)) && (size<(STEPPOS+60)))
    {
        fscanf(f,"%s",line);
        size+=(strlen(line) + 2);
        if (size>(STEPPOS+60)) break;
        if (emailParse(line, account))
        {
            if (account.length())
            {
                V[id].push_back(account);
            }
        }
    }
}

int emailParse(char* email, string& account)
{
    int index = 0;
    while (index<strlen(email))     account[index] = email[index++];
    account[index] = 0;
    return 1;
}

void* thread_proc(void* parameter)
{
    struct threaddata*  data = (struct threaddata*)parameter; 

    Free[data->id] = 0;

    if (data->pos>filesize) 
    {
        Free[data->id] = 1;
        return NULL;
    }

    unsigned char answer[PACKETSZ]; 

    readData(s_filein, data->pos, data->id);

        vector<string>::iterator itvec = V[data->id].begin(), itvecEnd = V[data->id].end();
    int vsize = V[data->id].size();
        for (int index=0;index<vsize;index++)          
    {
           char* email = (char*)V[data->id][index].c_str();
           char  acc[32], dom[32];
           int  i = 0;
           int  p = 0;
           while ((email[i]!='@') && (i<strlen(email))) acc[i] = email[i++];
           acc[i] = 0;
           i+=1;
           while (i<strlen(email))    dom[p++] = email[i++];
             dom[p] = 0;

           int flag = 0;

           string sdom = dom;

             FILE* f=fopen("r.txt","a");
           fprintf(f,"%s@%s\n", acc, dom);
           fclose(f);

           


           if (res_search(dom, C_IN, T_MX, static_cast<u_char*>(answer), sizeof(answer))>0) flag = 1;
           if (!flag) if (res_search(dom, C_IN, T_MX, static_cast<u_char*>(answer), sizeof(answer))>0) flag = 1;
           if (flag)
            {
            FILE* f=fopen(s_filegood,"a");
            fprintf(f,"%s\n", email);
            fclose(f);
           } else
           {
            FILE* f=fopen(s_filebad,"a");
            fprintf(f,"%s\n", email);
            fclose(f);
           }


        }

    Free[data->id] = 1;

    return NULL;
}


long getFileSize(char* filename)
{
    struct stat st;
    FILE* f = fopen(filename,"r");
    fstat(fileno(f), &st);
    fclose(f);
    return st.st_size;
}


А вот этот кусок кода у меня чекает на MX записи. Если его закоментировать то все Ок, иначе сегм. фаулт :



if (res_search(dom, C_IN, T_MX, static_cast<u_char*>(answer), sizeof(answer))>0) flag = 1;
           if (!flag) if (res_search(dom, C_IN, T_MX, static_cast<u_char*>(answer), sizeof(answer))>0) flag = 1;
           if (flag)
            {
            FILE* f=fopen(s_filegood,"a");
            fprintf(f,"%s\n", email);
            fclose(f);
           } else
           {
            FILE* f=fopen(s_filebad,"a");
            fprintf(f,"%s\n", email);
            fclose(f);
           }



С памятью я вроде нормально работаю, ну и с тредами верно обращаюсь.
Re: Segmentation fault
От: Ekin  
Дата: 02.06.04 01:11
Оценка:
Здравствуйте, alexora, Вы писали:

A>Я вот написал софтину, которая чекает мыла на валидатность. Она у меня тредовая. Кол. тредов указываешь. Каждый тред считывает определенное кол. бай с файла и чекает мыла на MX записи. Чекаю я через
res_search
функцию. Тестирование я проводил при 500 тредах, каждый тред считывал по 10кб данных с файла. Прикол в том, что если закоментировать кусок кода, который чекает на MX записи, то все пашет (файл при єтом парсится тредами и переписывается в другой). Если оставить этот кусок кода, то на середине проверки вываливается Segmention fault Как это понять ?


A>Вот весь код :



A>[ccode]

A>#include <sys/types.h>
A>#include <stdio.h>
A>#include <pthread.h>
A>#include <g++/vector>
A>#include <g++/string>
A>#include <netinet/in.h>
A>#include <arpa/nameser.h>
A>#include <resolv.h>
A>#include <g++/iostream>
A>#include <sys/stat.h>
A>#include <unistd.h>
A>#include <g++/algorithm>


A>#define MAXTHREADCOUNT 500

A>#define MINTHREADCOUNT 1
A>#define STEPPOS 10240

For users of C and C++ compilers without support for the -pthread switch,
you must ensure that the C preprocessor symbol _REENTRANT is defined before
including any system header file. One way to accomplish this is to compile
the application as follows:

cc -c myprog.c -D_REENTRANT

То есть тебе нужны thread-safe версии библиотек. Вот такие три строки _перед_ всеми инклюдами тебе помогут
#ifndef _REENTRANT
#define _REENTRANT
#endif // _REENTRANT
или действительно задай этот define в опциях компиляции.
Re: Segmentation fault
От: Vamp Россия  
Дата: 02.06.04 07:34
Оценка:
а gdb where что говорит?
Да здравствует мыло душистое и веревка пушистая.
Re: Segmentation fault
От: raskolnikov  
Дата: 02.06.04 07:36
Оценка:
Здравствуйте, alexora, Вы писали:

A>Я вот написал софтину, которая чекает мыла на валидатность. Она у меня A>тредовая. ...


Danila: A po russki eto kak?
Marlyn: Dasha!
Re[2]: Segmentation fault
От: alexora  
Дата: 02.06.04 09:41
Оценка:
А по подробней можно узнать что за -D_REENTRANT
Почему -pthread не катит ?
Re[3]: Segmentation fault
От: Ekin  
Дата: 02.06.04 11:17
Оценка:
Здравствуйте, alexora, Вы писали:

A>А по подробней можно узнать что за -D_REENTRANT

A>Почему -pthread не катит ?

Опция -pthread должна катить, судя по докам. А что этот дефайн помог, а -pthread само по себе не помогло?
Re[4]: Segmentation fault
От: Ekin  
Дата: 02.06.04 11:34
Оценка:
Здравствуйте, Ekin, Вы писали:

E>Здравствуйте, alexora, Вы писали:


A>>А по подробней можно узнать что за -D_REENTRANT

A>>Почему -pthread не катит ?

E>Опция -pthread должна катить, судя по докам. А что этот дефайн помог, а -pthread само по себе не помогло?


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

Реентрантные функции, это те в которые можно зайти снова, когда другой вызов еще не вышел -- например при рекурсии или из другого треда. В частности, это значит, что эти функции не используют статичесие данные, если только они не константные или защищены мьютексом.
Бывает и вот такие смешные случаи нереентрантности в одном треде:
printf( "%s -> %s\n", inet_ntoa(ip_src), inet_ntoa(ip_dst));
напечатает всегда два раза адрес ip_dst, несмотря на намерение вложенное в этот принт программистом )
(потому что библиотечная функция inet_ntoa очевидно возвращает указатель на свой статический буфер.)
Иногда реентрантность дорго обходится по памяти и времени. А треды пользуют все же не часто. Поэтому и бывают две версии библиотек.
Re: Segmentation fault
От: butcher Россия http://bu7cher.blogspot.com
Дата: 02.06.04 11:46
Оценка:
Здравствуйте, alexora.

Вы писали 2 июня 2004 г., 2:00:53:
a>
a> if (res_search(dom, C_IN, T_MX, static_cast<u_char*>(answer), sizeof(answer))>0) flag = 1;
a>


а если попробовать заменить этот код, примерно таким
Автор: butcher
Дата: 17.03.04
?
--
С уважением, butcher
Posted via RSDN NNTP Server 1.8

Нет ничего невозможного..
Re: Segmentation fault
От: Ekin  
Дата: 02.06.04 20:05
Оценка:
Здравствуйте, alexora, Вы писали:

A>Я вот написал софтину, которая чекает мыла на валидатность. Она у меня тредовая. Кол. тредов указываешь. Каждый тред считывает определенное кол. бай с файла и чекает мыла на MX записи. Чекаю я через
res_search
функцию. Тестирование я проводил при 500 тредах, каждый тред считывал по 10кб данных с файла. Прикол в том, что если закоментировать кусок кода, который чекает на MX записи, то все пашет (файл при єтом парсится тредами и переписывается в другой). Если оставить этот кусок кода, то на середине проверки вываливается Segmention fault Как это понять ?


A>Вот весь код :




A> pthread_create(&threads[itemindex], NULL, &thread_proc, &MID[itemindex]);

A> filepos+=STEPPOS;


A> for (itemindex=0;itemindex<threadcount;itemindex++) pthread_join(threads[itemindex], NULL);


Появилась еще одна мысль. В дефолтной сборке ядра линукса максимальное число тредов на процесс 256. Ты не проверяешь создался у тебя тред или нет, то есть фактически ты не знаешь проинициализировлаись ли у тебя threads[itemindex], а потом вызываешь pthread_join на нем. Когда ты комментируешь res_search треды быстро заканчиваются, и их число не успевает превысить 256. Когда же ты резольвишь, треды работают долго и на 257 треде твоя прога валится.

если ты в линуксе работаешь и под bash-ом, ты можешь сделать ulimit -с unlimited, потом после того как прога свалится и скинет кору сказать gdb myprog core, а уже в gdb сказать bt, конечно дебаггером отлаживать многотредовые проги практически невозможно, но ты увидешь все-таки в каком месте прога свалилась, особенно если компилил с -g опцией
Re[2]: Segmentation fault
От: alexora  
Дата: 03.06.04 12:52
Оценка:
Здравствуйте, Ekin, Вы писали:

Да прикол в том , что прога валится и при 10 тредах.
Хоть убей, не могу вдуплить в чем проблема.
Или в res_search или в _REENTRANT или еще в чем то
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.