Hello, all.Есть проблема с многопоточным приложением при статической компиляции.
Программа выглядит примерно такmain ()
{for (i = 0; i<NUM_SITES; i++)
pthread_create (&thread[indexes[i]], NULL, work_funct, (void*) &indexes[i]);
for (i = 0; i<NUM_SITES; i++)
pthread_join (thread[indexes[i]], NULL);
}void *work_funct
{....
n = 0;
printf ("!!!!!!!\n");
do
{
if (connect(sock, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) == -1)
{
if(n == NUM_CONNECTIONS)
{
perror ("connect()");
return;
}
else
{
n++;
}
}
printf("!!!!\n");
}
while (n > 0);.....
}Вывод программы:
!!!!!!!
KilledЕсли программу компилить без ключа -static, то всё работает.
Если запустить всего один(любой по номеру) процесс (при компиляции со -static), то всё работает.
Не работае только при статической компиляции и кол-ве прцессов больше 1.Строчка компиляции
gcc -o client3 client5.c `xml2-config --cflags` `pcre-config --cflags-posix --libs-posix` -lrt -static `xml2-config --libs` -WallВерсия gcc
# gcc -v
Reading specs from /usr/lib/gcc-lib/i586-suse-linux/3.3.3/specs
Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --enable-languages=c,c++,f77,objc,java,ada --disable-checking --libdir=/usr/lib --enable-libgcj --with-gxx-include-dir=/usr/include/g++ --with-slibdir=/lib --with-system-zlib --enable-shared --enable-__cxa_atexit i586-suse-linux
Thread model: posix
gcc version 3.3.3 (SuSE Linux)система Linux SuSE 9.1.
Ранее компилировал gcc-3.2.2 на системе Red Hat 9. Всё было ок.
Буду благодарен за любые подсказки-наводки, так-что если у кого есть мысли по этому поводу - пишите.
Спасибо.
А какие у вас glibc и ядро? и библиотека потоков.
>А какие у вас glibc и ядро? и библиотека потоков.# rpm -qa | grep glibc
glibc-locale-2.3.3-98
glibc-i18ndata-2.3.3-98
glibc-2.3.3-97
glibc-info-2.3.3-98
glibc-devel-2.3.3-97# uname -r
2.6.4-52-defaultКак узнать какая библиотека потоков?
При компиляции пишу -lpthread.
>>А какие у вас glibc и ядро? и библиотека потоков.
>
> # rpm -qa | grep glibc
>glibc-locale-2.3.3-98
>glibc-i18ndata-2.3.3-98
>glibc-2.3.3-97
>glibc-info-2.3.3-98
>glibc-devel-2.3.3-97
>
># uname -r
>2.6.4-52-default
>
>Как узнать какая библиотека потоков?
>При компиляции пишу -lpthread.
Библиотека называется /usr/compat/linux/lib/libpthread.so.0
>>
>>Как узнать какая библиотека потоков?
>>При компиляции пишу -lpthread.
>Библиотека называется /usr/compat/linux/lib/libpthread.so.0у меня нет каталога /usr/compat/. Нашёл файл libpthread.so в /usr/lib.
Вот его содержимое
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib/libpthread.so.0 /usr/lib/libpthread_nonshared.a )Нашёл так же файл /lib/libpthread.so.0 . Что с ним сделать, чтобы узнать версию библиотеки?
Я погуглил, и все что приходит в голову это добавить вызов xmlInitParser() если у вас его там нет. Попробуйте откомпилировать и запустить это на другой машине.
и вообще, если вам интересно следующий код у меня на linux-2.6.8.1, glibc-2.3.3, nptl работает#include <pthread.h>
#include <stdlib.h>void *work_funct(void *i);
main ()
{
int NUM_SITES=10, i;
pthread_t *thread = malloc(sizeof(pthread_t)*NUM_SITES);
for (i = 0; i<NUM_SITES; i++)
pthread_create (&thread[i], NULL, work_funct, (void*)i);
for (i = 0; i<NUM_SITES; i++)
pthread_join (thread[i], NULL);
}void *work_funct(void *i)
{
int NUM_CONNECTIONS=10;
int n = 0;
printf ("!!!!!!!\n");
do
{
if (/*connect(sock, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) == -1*/1)
{
if(n == NUM_CONNECTIONS)
{
perror ("connect()");
return;
}
else
{
n++;
}
}
printf("!!!!\n");
}
while (n > 0);}
компилил cc test.c -lphtread -static
>и вообще, если вам интересно следующий код у меня на linux-2.6.8.1, glibc-2.3.3,
>nptl работает> if (/*connect(sock, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) ==
>-1*/1)>
>компилил cc test.c -lphtread -staticСпасибо. Я тоже дошёл до функции коннект.
>Я погуглил, и все что приходит в голову это добавить вызов >xmlInitParser() если у вас его там нет. Попробуйте откомпилировать и >запустить это на другой машине.
xmlInitParser() вызывается позже. До этого момента нет ни одного обращения к функциям библиотеки libxml. Если откомпилировать это на SuSE и запустить на другой машине, то результат тот же.
А если компилировать на другой машине, то всё ок. В вопросе это описано(насчёт компиляции на другой машине).
Откуда должен следовать вывод, но какой? Напрашивается, что на SuSE кривой компилятор, но судя по опыту - это вряд ли. Скорей у программера руки кривые.Есть ли ещё идеи? Не знаю куда копать:(.
>Вывод программы:
>!!!!!!!
>KilledЭтот Killed пишет ваша программа или ядро? Просто непонятно, за что ее так, segfault или resource limit там, это первое что надо выяснить.
>>Вывод программы:
>>!!!!!!!
>>Killed
>
>Этот Killed пишет ваша программа или ядро? Просто непонятно, за что ее
>так, segfault или resource limit там, это первое что надо выяснить.
>Это пишет не программа. Значит ядро. Как выяснить segfault or resource limit?
ну, значитца, надо разрешить core:
ulimit -c 999999 для bash
и потом если после запуска появится файл core.etc... загрузить его в отладчик
gdb program-file core-filegdb расскажет, за что ее убили.
либо просто запускайте в отладчике:
gdb program-file
(gdb) run
>ну, значитца, надо разрешить core:
>ulimit -c 999999 для bashЛучше `ulimit -c unlimited` - по правде говоря, мне не приходилось
видеть core-файлы размером более 999999 x 512 ~ 50 MB, но чем чёрт
не шутит, мало ли какая у человека прога.>и потом если после запуска появится файл core.etc... загрузить его в
>отладчикИли сразу в отладчике загрузить и из-под него запустить. В некоторых
специфических конфигурациях отладчик не может нормально core прочитать.
Я с таким сталкивался под Tru64.
Спасибо,выяснил, прогу убивают по
segmentation failed.но к чему segmentation failed когда происходит коннект?
>Спасибо,
>
>выяснил, прогу убивают по
>segmentation failed.
>
>но к чему segmentation failed когда происходит коннект?если бы вы потрудились привести весь код..
а так - хбз.// wbr
Если это поможет --
вот:#define NDEBUG
//#define TIME
//#define WRITE
//#define DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>#include <libxml/parser.h>
#include <libxml/tree.h>
#include <time.h>/* Windows-System */
#ifdef _WIN32
#include <winsock.h>
#include <io.h>/* Unix-System */
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <pcreposix.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#endif
#define HTTP_PORT 80#define NUM_SITES 46
#define MAX_NUM_TEG 5
#define BUFF_CONTEXT 4096#define NUM_CONNECTIONS 10
#define NUM_NoT 3
#define NUM_PF 3/*definishions of errors*/
#define NAMES_OF_TEGS_IS_NOT_FOUND 1
#define PARSE_FAIL 2#define ERR_REGCOMP 11
#define ERR_REGEXEC 12
#define MATCHPTR_RM_EO_EQ_MINUS_1 13#define ERR_PTRNULL 31
#define ERR_IMPOSSIBLE 34
#define ERR_REGNOTFOUND 35int Status[NUM_SITES] = {0};
pthread_mutex_t flag;
double TIME_OUT = 2;void work_funct (void *i);
int RasborXML (const char *teg[MAX_NUM_TEG], const int kol_teg, const char *xml, const int j);
int RasborHTML (const char *teg[MAX_NUM_TEG], const int kol_teg, char *html, const int j);
int str_repl_reg_null (char *str, const char *pattern);int main (int argc, char *argv[])
{if (( (argc-5)%4 ) || (argc < 13))
{
fprintf (stderr, "Notice: Incorrect agguments \
for parser. Contact to the developers.\n");
return (-1);
}strncpy (hostnames[25], argv[5], 32);
strncpy (hostnames[26], argv[6], 32);TIME_OUT = atof(argv[4]);
/*struct timespec tm1, tm2;clock_gettime(CLOCK_REALTIME, &tm1);*/
pthread_t thread[NUM_SITES];
int i, j;
for (i = 0; i<NUM_SITES; i++)
indexes[i] = i;for (i = 9; i<argc; i+=4)
for (j = 0; j<NUM_SITES; j++)
if (!strcmp (SiteIdentificators[j], argv[i]))
{
Status[j] = 1;
sprintf (Site_id[j], argv[i+1]);
sprintf (Site_id2[j], argv[i+2]);
sprintf (Num_results[j], argv[i+3]);
break;
}if (Status[9])
{
sprintf (BaseStrings[9], "/feed/xml.aspx?pn=1&filter=no&st=%s&rid=%s&",
argv[7], argv[8]);
}if (Status[28])
{
sprintf (BaseStrings[28], "%s%s%s", SubArrayBeg[0], Site_id[28], SubArrayEnd[0]);
}if (Status[30])
{
sprintf (BaseStrings[30], "%s%s%s", SubArrayBeg[1], Site_id[30], SubArrayEnd[1]);
}if (Status[40])
{
sprintf (BaseStrings[40], "%s%s%s%s%s", SubArrayBeg[2],
Site_id2[40],
SubArrayMiddl[2],
Num_results[40],
SubArrayEnd[2]);}
for (i = 0; i<NUM_SITES; i++)
if (Status[i])
{
int b = 0;
if (!strcmp (Site_id2[i], "NULL"))
b = 1;
else if (!strcmp (Site_id2Names[i], ""))
b = 1;
sprintf (Commands[i], "%s%s%s%s%s%s%s%s%s%s%s%s%s", BaseStrings[i],
KeywordNames[i], argv[1],
IpNames[i], ((!strcmp (IpNames[i], ""))?"":argv[2]),
Site_idNames[i], ((!strcmp (Site_idNames[i], ""))?"":Site_id[i]),
Num_resultsNames[i],((!strcmp (Num_resultsNames[i], ""))?"":Num_results[i]),
((!strcmp (Site_id2[i], "NULL"))?"":Site_id2Names[i]), (b?"":Site_id2[i]),
Sub_idNames[i], ((!strcmp (Sub_idNames[i], ""))?"":argv[3]));
}
#ifdef WRITE
for (i = 0; i<NUM_SITES; i++)
if (Status[i])
printf("%s%s\n",hostnames[i], Commands[i]);
#endiffor (i = 0; i<NUM_SITES; i++)
if (Status[i])
pthread_create (&thread[indexes[i]], NULL, (void*)&work_funct, (void*) &indexes[i]);
for (i = 0; i<NUM_SITES; i++)
if (Status[i])
pthread_join (thread[indexes[i]], NULL);/*printf("Main thread done.\n");*/
pthread_mutex_destroy (&flag);
printf("\n");
return 0;
}
void work_funct(void *i)
{
alarm(TIME_OUT);
int *k=(int *)i;
int j=*k;printf("Process %d started.\n",j);
int sock;
struct sockaddr_in host_addr;
struct hostent *hostinfo;
const char *host, *file;
char command[1024];
char buf[1024];int bigbuf_index=0;
char bigbuf[204800];
unsigned int bytes_sent, bytes_recv;host = hostnames[j];
file = Commands[j];int kol_parse_fail = 0, kol_names_of_tegs = 0, n = 0;
/*
struct timespec tm1, tm2;
clock_gettime (CLOCK_REALTIME, &tm1);
*/
do
{
bigbuf[0] = 0;
bigbuf_index = 0;#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup (MAKEWORD(1, 1), &wsaData) != 0)
{
fprintf (stderr, "WSAStartup(): Kann Winsock nicht initialisieren.\n");
return;
}
#endifsock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
perror ("socket()");
return;
}memset( &host_addr, 0, sizeof (host_addr));
host_addr.sin_family = AF_INET;
host_addr.sin_port = htons (HTTP_PORT);
host_addr.sin_addr.s_addr = inet_addr (host);
if (host_addr.sin_addr.s_addr == INADDR_NONE)
{
hostinfo = gethostbyname (host);
if (hostinfo == NULL)
{
perror ("gethostbyname()");
return;
}
memcpy((char*) &host_addr.sin_addr.s_addr, hostinfo->h_addr, hostinfo->h_length);
}n = 0;
do
{
printf ("Before connect\n");
if (connect(sock, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) == -1)
{
printf ("After connect\n");
if(n == NUM_CONNECTIONS)
{
perror ("connect()");
return;
}
else
{
printf ("After connect\n");
n++;
}
}
}
while (n > 0);sprintf (command, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-agent: compatible\r\n\r\n", file, host);
bytes_sent = send (sock, command, strlen (command), 0);
if (bytes_sent == -1)
{
perror ("send()");
return;
}while ((bytes_recv = recv (sock, buf, sizeof(buf), 0)) > 0)
{
if ( (bigbuf_index + bytes_recv) > 204800)
return;
memcpy(bigbuf + bigbuf_index, buf, bytes_recv);
bigbuf_index += bytes_recv;
}bigbuf[bigbuf_index] = 0;
if (bytes_recv == -1)
{
perror ("recv()");
return;
}char *s1 = strstr(bigbuf,"<");
if (!strcmp (SiteIdentificators[j], "Espotting"))
s1 = bigbuf;
if (!s1)
{
fprintf (stderr, "Error\n");
return;
}
if ( (!strcmp (SiteIdentificators[j], "Google")) ||
(!strcmp (SiteIdentificators[j], "Yahoo")) ||
(!strcmp (SiteIdentificators[j], "AltaVista")) ||
(!strcmp (SiteIdentificators[j], "Dmoz")) ||
(!strcmp (SiteIdentificators[j], "SearchHawk")) ||
(!strcmp (SiteIdentificators[j], "MrWordSmith")) ||
(!strcmp (SiteIdentificators[j], "MSN")) ||
(!strcmp (SiteIdentificators[j], "Espotting")) ||
(!strcmp (SiteIdentificators[j], "SearchDrifter")) )
{
n = RasborHTML (teg1[j], MAX_NUM_TEG, s1, j);
if (n != 0)
{
return;
}
}
else
n = RasborXML (teg1[j],MAX_NUM_TEG,s1, j);if (n == PARSE_FAIL)
{
kol_parse_fail++;
if (kol_parse_fail == NUM_PF)
{
fprintf (stderr, "Failed to parse... Site %s.\n", SiteIdentificators[j]);
return;
}
}
if (n == NAMES_OF_TEGS_IS_NOT_FOUND)
{
kol_names_of_tegs++;
if (kol_names_of_tegs == NUM_NoT)
{
#ifdef WRITE
fprintf (stderr, "Names of tegs are not found. Site %s.\n", SiteIdentificators[j]);
#endif
return;
}
}
}
while (n != 0);#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif/*printf("Process %d done.\n",j);*/
return;
}Пишет
Process 1 was started.
Process 2 was started.Before connect.
KilledЕсли нужен полностью файл исходника - могу скинуть на мыло архив. Напишите адрес мыла на мыло jarunda@mail.ru.
Спасибо.
Попробуй скормить компилеру ключик -pthread помимо всего остального. Он тогда более щадящий к потокам бинарь конструирует, бывает что помогает.
Вообще-то строка:if (connect(sock, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) == -1)
не совсем верная.
Нужно использовать не sizeof(struct sockaddr), а sizeof(host_addr) или на худой конец sizeof(struct sockaddr_in).
Не следует забывать, что struct sockaddr и struct sockaddr_in имеют _разную_ длину. Может и segfault отсюда вылезает.
>strncpy (hostnames[25], argv[5], 32);
>strncpy (hostnames[26], argv[6], 32);это что такое и откуда?
>for (i = 9; i<argc; i+=4)
> for (j = 0; j<NUM_SITES; j++)
> if (!strcmp (SiteIdentificators[j], argv[i]))
> {
> Status[j] = 1;
> sprintf (Site_id[j], argv[i+1]);
> sprintf (Site_id2[j], argv[i+2]);
> sprintf (Num_results[j], argv[i+3]);
> break;
> }
>
>if (Status[9])
>{
> sprintf (BaseStrings[9], "/feed/xml.aspx?pn=1&filter=no&st=%s&rid=%s&",
> argv[7],
>argv[8]);
>}
>
>if (Status[28])
>{
> sprintf (BaseStrings[28], "%s%s%s", SubArrayBeg[0], Site_id[28], SubArrayEnd[0]);
>}
>
>if (Status[30])
>{
> sprintf (BaseStrings[30], "%s%s%s", SubArrayBeg[1], Site_id[30], SubArrayEnd[1]);
>}
>
>if (Status[40])
>{
> sprintf (BaseStrings[40], "%s%s%s%s%s", SubArrayBeg[2],
> Site_id2[40],
> SubArrayMiddl[2],
> Num_results[40],
> SubArrayEnd[2]);
>
>}
>
>for (i = 0; i<NUM_SITES; i++)
> if (Status[i])
> {
> int b = 0;
> if (!strcmp (Site_id2[i], "NULL"))
> b = 1;
> else if (!strcmp (Site_id2Names[i], ""))
> b = 1;
> sprintf (Commands[i], "%s%s%s%s%s%s%s%s%s%s%s%s%s", BaseStrings[i],
> KeywordNames[i], argv[1],
> IpNames[i], ((!strcmp (IpNames[i], ""))?"":argv[2]),
> Site_idNames[i], ((!strcmp (Site_idNames[i], ""))?"":Site_id[i]),
> Num_resultsNames[i],((!strcmp (Num_resultsNames[i], ""))?"":Num_results[i]),
> ((!strcmp (Site_id2[i], "NULL"))?"":Site_id2Names[i]), (b?"":Site_id2[i]),
> Sub_idNames[i], ((!strcmp (Sub_idNames[i], ""))?"":argv[3]));
> }
>#ifdef WRITE
>for (i = 0; i<NUM_SITES; i++)
> if (Status[i])
> printf("%s%s\n",hostnames[i], Commands[i]);
>#endifтут масса кода с использованием sprintf без проверки аргументов -> в любом месте может быть overflow -> SIGSEGV.
код переделать.
>for (i = 0; i<NUM_SITES; i++)
> if (Status[i])
> pthread_create (&thread[indexes[i]], NULL, (void*)&work_funct, (void*) &indexes[i]);что такое indexes и откуда?
>void work_funct(void *i)
однако, из потока возвращать нужно таки void *. переделать.
>{
> alarm(TIME_OUT);вы уверены, как именно поведут себя ваши потоки при работе с сигналами? signal handler per thread и пр.
> memset( &host_addr, 0, sizeof (host_addr));
> host_addr.sin_family = AF_INET;
> host_addr.sin_port = htons (HTTP_PORT);
> host_addr.sin_addr.s_addr = inet_addr (host);некоторые системы так-же требуют явной установки поля sin_len -> неплохо бы добавить:
host_addr.sin_len = sizeof(host_addr);> if (host_addr.sin_addr.s_addr == INADDR_NONE)
> {
> hostinfo = gethostbyname (host);
> if (hostinfo == NULL)
> {
> perror ("gethostbyname()");
> return;
> }
> memcpy((char*) &host_addr.sin_addr.s_addr, hostinfo->h_addr, hostinfo->h_length);
> }не факт, что значение возвращенного h_length будет раво или меньше sizeof(host_addr.sin_addr.s_addr) -> потенциальный overflow.
> n = 0;
> do
> {
> printf ("Before connect\n");
> if (connect(sock, (struct sockaddr *) &host_addr,
>sizeof(struct sockaddr)) == -1)таки скорее sizeof(struct sockaddr_in)
> sprintf (command, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-agent: compatible\r\n\r\n", file,
>host);buffer overflow
> while ((bytes_recv = recv (sock, buf, sizeof(buf), 0)) > 0)
> {
> if ( (bigbuf_index + bytes_recv) > 204800)
> return;
> memcpy(bigbuf + bigbuf_index, buf, bytes_recv);
> bigbuf_index += bytes_recv;
> }нет проверки на bytes_recv == 0 -> потеря рассоединения сокета.
ну и так далее.
// wbr