LINUX.ORG.RU

pthread + malloc = зависание


0

0

Есть довольно запутанная программа, у которой директивами условной компиляции (#ifdef..#endif) включается поддержка тредов. Если она включена и я вставляю free (malloc (1)); в любое место до использования MUTEX`ов, то она зависает (gdb показывает на функцию pthread_mutex_lock). Если такую строчку не вставлять или отключить поддержку тредов, то всё отлично. Как данная строка может влиять на состояние MUTEX`ов?

★★★

Конечно, трудно судить по такому сумбурному сообщению. Но, вообще-то, в качестве информации к размышлению -- каждый malloc в многонитковой программе обкладывается мутексами...

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

Угу. Смотрите, где в момент зависания находятся другие треды. Наверняка тоже в какой-нибудь блокировке, вызванной из malloc/free. Часто такое бывает, когда тред, обрабатывающий сложный системный запрос типа malloc/free/dlopen/dlsym/etc, получает сигнал и уходит по своим сигнальным делам, залочив системный мутекс.

jek_
()
Ответ на: комментарий от jek_

Когда я включаю efence или запускаю программу через valgrind, зависания не происходит (я не получаю никаких предупреждений и всё работает нормально).

> Смотрите, где в момент зависания находятся другие треды.

Программа треды хотя и может использовать, но в интересующем мне случае (когда всё завсисает) их не использует (нет вызовов pthread_create). Т.е. "других тредов" нет.

Где можно почитать про блокировки системного mutex`а при обработке сложных системных запросов? Кстати, dlopen у меня как раз используется (я им подключаю libreadline).

kmeaw ★★★
() автор топика
Ответ на: комментарий от kmeaw

> Когда я включаю efence или запускаю программу через valgrind,
> зависания не происходит (я не получаю никаких предупреждений и всё
> работает нормально).

В этом нет ничего удивительно, поскольку все отладочные средства так
или иначе меняют поведение программы.

> Программа треды хотя и может использовать, но в интересующем мне
> случае (когда всё завсисает) их не использует (нет вызовов
> pthread_create). Т.е. "других тредов" нет.

А что же тогда включают ваши директивы препроцессора? А что говорит gdb
по команде "info threads" после зависания?

Возможно, дело даже не тредах (не только в них), а просто куча как-нибудь
хитро побита, что вызов malloc/free вешается. Можно попробовать 
поиграть с переменной окружения MALLOC_CHECK_

> Где можно почитать про блокировки системного mutex`а

Нигде нельзя. Только в исходниках. Вообще следует понимать, что речь
не идёт о каком-то одном мутексе. Любая библиотечная функция общего
назначения, работающая с общими внутрисистемными данными, может
использовать свои мутексы или ещё какие-либо средства защиты шаренных
данных. В libdl свой механизм, свои мутексы; в глобальном аллокаторе -
свой механизм и свои блокировки.

jek_
()
Ответ на: комментарий от kmeaw

>Программа треды хотя и может использовать, но в интересующем мне случае (когда всё завсисает) их не использует (нет вызовов pthread_create).

Хотелось бы в этом дополнительно удостовериться (ps -eLf или thread info в gdb), потому что добиться ожидания мютекса при наличии лишь одной нити и описанным Вами способом крайне проблематично.

anonymous
()
Ответ на: комментарий от anonymous

> нафига malloc() (да ёщё каждый) обкладывать мьютексом?

Это загадка. Я думаю, автор немного не проснулся, когда это писал.

anonymous
()
Ответ на: комментарий от jek_

> А что же тогда включают ваши директивы препроцессора?

Они включают код, который отвечает за блокировку объектов и создание тредов.

(gdb) run index.tbs
Starting program: ./main index.tbs
[Thread debugging using libthread_db enabled]
[New Thread -1212242256 (LWP 8046)]
(всё повисло, жму Ctrl-C)
Program received signal SIGINT, Interrupt.
[Switching to Thread -1212242256 (LWP 8046)]
0xffffe410 in __kernel_vsyscall ()
(gdb) info threads
* 1 Thread -1212242256 (LWP 8046)  0xffffe410 in __kernel_vsyscall ()
(gdb) 

> Возможно, дело даже не тредах (не только в них), а просто куча как-нибудь хитро побита, что вызов malloc/free вешается. 

Можно ли определить это, используя valgrind и efence?

 >>  MALLOC_CHECK_=32767 ./main index.tbs 
malloc: using debugging hooks
(всё повисло)

Может ли возникать ошибка из-за того, что я делаю pthread_mutex_unlock тогда, когда mutex уже разлочен?

kmeaw ★★★
() автор топика
Ответ на: комментарий от anonymous

Я не обкладываю каждый malloc() mutex`ом, я обкладываю некоторые структуры данных тогда, когда они обрабатываются, а другой thread может сделать им free().

kmeaw ★★★
() автор топика
Ответ на: комментарий от Die-Hard

Во избежание недоразумений:

> каждый malloc в многонитковой программе обкладывается мутексами...

Я имел в виду не то, что программист должен что-то там обкладывать, а то, что _библиотечная_ реализация malloc() это делает.

Die-Hard ★★★★★
()

Я нашел причину зависания -- когда я отключил поддержку libdl, все нормализовалось. 
Спасибо всем, кто помог! Насчет libdl: что я делаю не так?

#ifdef LINUX
static void (*add_history) (char *) = NULL;
static void (*lib_using_history) (void) = NULL;
static char *(*readline) (char *) = NULL;
static void *(*clear_history) (void) = NULL;
static void *libhistory = NULL, *libreadline = NULL;
#endif

void init_func()
{
#ifdef LINUX
  libreadline = dlopen ("libreadline.so", RTLD_NOW);
  libhistory = dlopen ("libhistory.so", RTLD_NOW);

  if (libhistory && libreadline)
    {
      add_history = dlsym (libreadline, "add_history");
      lib_using_history = dlsym (libhistory, "using_history");
      readline = dlsym (libreadline, "readline");
      clear_history = dlsym (libhistory, "clear_history");
      if (lib_using_history)
        (*lib_using_history) ();
    }
#endif
}

void cleanup_func()
{
#ifdef LINUX
  if (clear_history)
    (*clear_history) ();

  if (libreadline)
    dlclose (libreadline);

  if (libhistory)
    dlclose (libhistory);
#endif
}

kmeaw ★★★
() автор топика
Ответ на: комментарий от kmeaw

Покажите ещё вывод gdb по команде "bt" после зависона.

> Может ли возникать ошибка из-за того, что я делаю pthread_mutex_unlock
> тогда, когда mutex уже разлочен?

Нет, такое поведение не может привести к зависанию. См. man pthread_mutex_unlock.

> Насчет libdl: что я делаю не так?

Да вроде всё хорошо. Возможно, проблема в библиотечных функциях, которые
вызываются: lib_using_history и clear_history.

Да, а что будет, если заменить флаг RTLD_NOW на RTLD_LAZY?

jek_
()
Ответ на: комментарий от jek_

> Покажите ещё вывод gdb по команде "bt" после зависона.

#0  0xffffe410 in __kernel_vsyscall ()
#1  0xb7f2178e in __lll_mutex_lock_wait () from /lib/libpthread.so.0
#2  0xb7f1e2e9 in _L_mutex_lock_42 () from /lib/libpthread.so.0
#3  0xb7f1e991 in pthread_mutex_unlock () from /lib/libpthread.so.0
#4  0x0806ac26 in metalock (obj=0x809a500) at tbpl.c:277
#5  0x0806aa52 in delete_object (object=0x809a500) at tbpl.c:212
#6  0x0806a97b in sys_destructor (object=0x809a500, tmp=0x809a350) at tbpl.c:176
#7  0x0806aaf4 in delete_object (object=0x809a350) at tbpl.c:231
#8  0x0806a97b in sys_destructor (object=0x809a350, tmp=0x809a210) at tbpl.c:176
#9  0x0806aaf4 in delete_object (object=0x809a210) at tbpl.c:231
#10 0x08068259 in unenv (scope=0x809a210) at control.c:151
#11 0x0806a234 in parse_single_token (start=0x807a178, current=0x809a500, env=0x807a088, token=0x8099780 "name", 
    ptr=0xbfee0a2c, garbage=0x0) at parser.c:742

kmeaw ★★★
() автор топика
Ответ на: комментарий от kmeaw

Очень странно. А что находится в файле tbpl.c на строке 277 и в её окрестности?

jek_
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.