The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
clone() и malloc(), !*! nikolayshm, 11-Янв-12, 13:30  [смотреть все]
Прошу помощи у знающих людей.

Создаю процессы с помощью clone() с флагами: CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD | CLONE_SYSVSEM.
Если добавить флаг CLONE_THREAD, то все работает нормально, но этот флаш не нужен.

При этом когда они начиют конкурировать между собой, возникает deadlock в функциях malloc()/free()

используется clone(), а не fork() потому что в приложении нужно шарить очень много данных.
используется clone(), а не pthread_create() потому что при смерти треда (seg fault) завершается сразу все приложение.
То есть хочется что бы и процессы между собой все делили, и при этом были независимы друг от друга в случае смерти.
В функциях glibc есть внутренние блокировки, непонятно только почему они заходят в deadlock.


Код для демонстрации:

int func(void *p)
{
    while (1) {
        p = (char *)malloc(6);
        memcpy(p, "12345\0", 5);
        free(p);
    }
}

#define     STACK_SIZE 1024*1024

int main()
{
    int i;
                                            
    for (i=0; i<10; i++) {
        void *stack = malloc(STACK_SIZE);
        int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD | CLONE_SYSVSEM;
        int id = clone(func, (char *)stack + STACK_SIZE, flags, NULL);
    }

    sleep(10000);

    return 0;
}

  • clone() и malloc(), !*! Вова, 14:59 , 11-Янв-12 (1)
    так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
    • clone() и malloc(), !*! nikolayshm, 16:09 , 11-Янв-12 (4)
      > так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.

      Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
      Все версии выдали:
      *** glibc detected *** *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x00002af4240008c0 ***
      В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb показал что ожидание внутри free.

      • clone() и malloc(), !*! me, 17:10 , 11-Янв-12 (7)
        >> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
        > Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
        > Все версии выдали:
        > *** glibc detected *** *** glibc detected *** ./a.out: double free or
        > corruption (fasttop): 0x00002af4240008c0 ***

        ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.

        > В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb
        > показал что ожидание внутри free.

        это больша на багу glibc похоже, хотя с таким кодом я не удивлён.

        • clone() и malloc(), !*! nikolayshm, 17:52 , 11-Янв-12 (8)
          >>> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
          >> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
          >> Все версии выдали:
          >> *** glibc detected *** *** glibc detected *** ./a.out: double free or
          >> corruption (fasttop): 0x00002af4240008c0 ***
          > ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.

          С одной стороны это логично, и это тоже первое о чем я подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.
          Да и malloc использует внутреннюю блокировку, что бы быть thread-safe, непонятно почему эта блокировка не спасает.
          Если обернуть внешний вызов malloc/free в mutex то проблема исчезает.


          >> В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb
          >> показал что ожидание внутри free.
          > это больша на багу glibc похоже, хотя с таким кодом я не
          > удивлён.

          Про код опишите, пожалуйста, что именно в нем плохо? Специально синтетический тест на конкуренцию malloc/free.

          • clone() и malloc(), !*! me, 19:30 , 11-Янв-12 (9)
            >>>> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
            >>> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
            >>> Все версии выдали:
            >>> *** glibc detected *** *** glibc detected *** ./a.out: double free or
            >>> corruption (fasttop): 0x00002af4240008c0 ***
            >> ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.
            > С одной стороны это логично, и это тоже первое о чем я
            > подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.

            так вы-ж его не иначе с -pthread собираете? :)

            > Да и malloc использует внутреннюю блокировку, что бы быть thread-safe,

            без флага pthread? или с флагом но без pthread_create? серьезно? :)

            > непонятно почему
            > эта блокировка не спасает.
            > Если обернуть внешний вызов malloc/free в mutex то проблема исчезает.
            >>> В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb
            >>> показал что ожидание внутри free.
            >> это больша на багу glibc похоже, хотя с таким кодом я не
            >> удивлён.
            > Про код опишите, пожалуйста, что именно в нем плохо? Специально синтетический тест
            > на конкуренцию malloc/free.

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

            • clone() и malloc(), !*! nikolayshm, 21:12 , 11-Янв-12 (10)
              >[оверквотинг удален]
              >>>> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
              >>>> Все версии выдали:
              >>>> *** glibc detected *** *** glibc detected *** ./a.out: double free or
              >>>> corruption (fasttop): 0x00002af4240008c0 ***
              >>> ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.
              >> С одной стороны это логично, и это тоже первое о чем я
              >> подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.
              > так вы-ж его не иначе с -pthread собираете? :)
              >> Да и malloc использует внутреннюю блокировку, что бы быть thread-safe,
              > без флага pthread? или с флагом но без pthread_create? серьезно? :)

              Я собирал и без -pthread и с ней. добавлял -D_REENTRANT - все без результатно.

              но... по вашему "намеку" попробовал добавить в код pthread_create(), который создает тред и сразу его закрывает. все заработало.
              Очевидно что pthread_create что то проинициализировал. Я смотрел его код, но инициализацией связанных с памятью или локами не нашел (кроме стека).

              Спасибо Вам за помощь.
              Если возможно, подскажите, что именно инициализирует pthread_create()? что бы не использовать его как "хак".

              • clone() и malloc(), !*! me, 23:11 , 11-Янв-12 (11)
                >[оверквотинг удален]
                >>> подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.
                >> так вы-ж его не иначе с -pthread собираете? :)
                >>> Да и malloc использует внутреннюю блокировку, что бы быть thread-safe,
                >> без флага pthread? или с флагом но без pthread_create? серьезно? :)
                > Я собирал и без -pthread и с ней. добавлял -D_REENTRANT - все
                > без результатно.
                > но... по вашему "намеку" попробовал добавить в код pthread_create(), который создает тред
                > и сразу его закрывает. все заработало.
                > Очевидно что pthread_create что то проинициализировал. Я смотрел его код, но инициализацией
                > связанных с памятью или локами не нашел (кроме стека).

                не, я имел ввиду pthread_create для создания потока вместо clone. Вы показали ваш собственный фокус. (весьма занятный, кстати. но я-бы не рассчитывал, что этот код будет работать всегда)

                > Спасибо Вам за помощь.

                незачто и судя по-тому, что вы хотели clone() "потому что при смерти треда (seg fault) завершается сразу все приложение." - вы еще не пробовали посылать sigsegv ни одному из ваших "работающих" клонов. SIGSEGV, кстати, маскируется и обрабатывается.

                > Если возможно, подскажите, что именно инициализирует pthread_create()? что бы не использовать
                > его как "хак".

                это "хак" и я-бы его не использовал.

                • clone() и malloc(), !*! nikolayshm, 00:29 , 12-Янв-12 (12)
                  > незачто и судя по-тому, что вы хотели clone() "потому что при смерти
                  > треда (seg fault) завершается сразу все приложение." - вы еще не
                  > пробовали посылать sigsegv ни одному из ваших "работающих" клонов. SIGSEGV, кстати,
                  > маскируется и обрабатывается.

                  Этот момент я хорошо тестировал. SIGSEGV вызывал разными способами.
                  В случае с клонами (с указанными флагами) SIGSEGV ловится слоном, вызывается exit() и клон умирает. Родитель обрабатывает waitpid и продолжает работать.
                  В случае с тредами (pthread_create или флаг CLONE_THREAD) SIGSEGV тоже ловится, но ловит его родитель и продолжать работать не может. Умирает родитель и умирают все поражденные треды.

                  • clone() и malloc(), !*! pavlinux, 18:49 , 14-Янв-12 (13)
                    Блин, вы С учить будете? А то glibc, треды... придумали тоже... :)

                    У Вас указатель *stack ВСЕ ВРЕМЯ указывает на один и тот же сегмент,
                    над которым затем трахаются по 10 копий malloc и free!!!
                    Да, на уровне ядра есть блокировки, собственно благодаря которым вы и получаете SIGSEGV,
                    а не смерть всего компа.

                    Ниже я показал, что надо юзать указатель на указатель (можно массив указателей)

                    • clone() и malloc(), !*! nikolayshm, 20:04 , 14-Янв-12 (15)
                      > Блин, вы С учить будете? А то glibc, треды... придумали тоже... :)

                      Буду рад, если Вы подскажите что почитать для получения новых знаний.

                      > У Вас указатель *stack ВСЕ ВРЕМЯ указывает на один и тот же
                      > сегмент,
                      > над которым затем трахаются по 10 копий malloc и free!!!

                      Мой код:
                      for (i=0; i<10; i++) {
                              void *stack = malloc(STACK_SIZE);
                      }

                      переменной stack присывается новое значение, так что *stack никак не может указывать на одинаковый сегмент памяти.


                      > Ниже я показал, что надо юзать указатель на указатель (можно массив указателей)

                      Кусок Вашего кода:

                      stack = malloc(STACK_SIZE);
                      for (i = 0; i < 10; i++) {
                         *stack = (void *)(STACK_SIZE + (char *)stack);
                         clone(func, stack, FLAGS, NULL);

                      Вы выделили память размером STACK_SIZE,
                      затем в первый байт записали ссылку на конец выделенной памяти
                      передали в clone ссылку на выделенную память.

                      У доке четко написано:
                      The child_stack argument specifies the location of the stack used by the child process. ... The calling process must therefore set up memory space for the child stack and pass a pointer to this space to clone().
                      В переводе это означает что передавать нужно ссылку на память, а не ссылку на ссылку на память.
                      Даже, если предположить что нужно передавать последнее, то Ваш код все равно не работает так как во все 10 клонов он передаст один и тот же указатель.


                      P.S. Ваш код я скомпилировал и запустил, как результат:
                      kernel: a.out[28746]: segfault at 0000000000000000 rip 0000000000000000 rsp 00002b18a9b79008 error 14

                      • clone() и malloc(), !*! pavlinux, 00:59 , 15-Янв-12 (16)
                        >[оверквотинг удален]
                        > В переводе это означает что передавать нужно ссылку на память,
                        > а не ссылку на ссылку на память.

                        Чуток не правильно понимаешь свойства работы с указателем на указатель.
                        Ну на, в твоем виде


                        #include <stdio.h>
                        #include <stdlib.h>
                        #include <unistd.h>
                        #include <string.h>
                        #include <sched.h>
                        #include <signal.h>


                        #define STACK_SIZE (1024*1024)
                        #define FLAGS (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_SYSVSEM|SIGCHLD)

                        int func(void *p) {
                            
                            while (1) {
                                   p = (char *)malloc(6);
                                   memcpy(p, "12345\0", 6);
                                   free(p);
                            }
                        }

                        int main() {

                            int i;
                            void **stack;
                            
                            for (i = 0; i < 10; i++) {
                                 stack = (void **)malloc(STACK_SIZE);
                                 clone(func, stack, FLAGS, NULL);
                            }

                            sleep(10);
                            return 0;
                        }


                        • clone() и malloc(), !*! nikolayshm, 04:02 , 15-Янв-12 (18)
                          >>[оверквотинг удален]
                          >> В переводе это означает что передавать нужно ссылку на память,
                          >> а не ссылку на ссылку на память.
                          > Чуток не правильно понимаешь свойства работы с указателем на указатель.
                          > Ну на, в твоем виде

                          С Вашего позволения, тоже перейду на "ты".

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

                          Что касается кода, правильно ли я понял фразу "Ну на, в твоем виде" - означает, что 2 кода которые ты привел они идентичны, только "вид" разный?
                          Для наглядности:

                          первый:

                           
                              void **stack;
                              for (i = 0; i < 10; i++) {
                                   stack = (void **)malloc(STACK_SIZE);
                                   clone(func, stack, FLAGS, NULL);
                              }


                          второй:

                           
                              void **stack;
                              stack = malloc(STACK_SIZE);
                              for (i = 0; i < 10; i++) {
                                  *stack = (void *)(STACK_SIZE + (char *)stack);
                                  clone(func, stack, FLAGS, NULL);
                              }

                        • clone() и malloc(), !*! pavlinux, 14:50 , 15-Янв-12 (20)
                          >>>[оверквотинг удален]

                          Короче не ..би моск

                           
                          static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

                          int func(void *ptr) {

                              char *msg = (char *) ptr;

                              while (1) {
                                  pthread_mutex_lock(&lock);
                                    msg = malloc( 6);
                                    strncpy(msg, "12345\0", 6);
                                    free(msg);
                                  pthread_mutex_unlock(&lock);
                              }
                              return 0;
                          }

                          Кстати, размер стека лучше узнавать у getrlimit(RLIMIT_STACK, rlim) ...

  • clone() и malloc(), !*! pavlinux, 16:26 , 11-Янв-12 (5)

    int func(void *p)
    {
            while (1) {
                    p = (char *)malloc(6);
                    memcpy(p, "12345\0", 6);
                    free(p);
            }
    }

    #define STACK_SIZE (1024*1024)
    #define FLAGS (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_SYSVSEM|SIGCHLD)

    int main()
    {
            int i;
            void **stack;

            stack = malloc(STACK_SIZE);
            for (i = 0; i < 10; i++) {
                *stack = (void *)(STACK_SIZE + (char *)stack);
                 clone(func, stack, FLAGS, NULL);
            }
            sleep(10000);
            return 0;
    }

    Криво, ибо пример такой.
    Давай реальную задачу.

  • clone() и malloc(), !*! svn, 03:19 , 15-Янв-12 (17)
    > При этом когда они начиют конкурировать между собой, возникает deadlock в функциях
    > malloc()/free()

    Конечно возникает. Потому что память одного процесса неожиданно редактирует другой процесс.

    Если какой-то поток вызывает SIGSEGV - значит вся память испорчена. Общая, всего процесса!!
    Ничего хорошего в работе программы с испорченной памятью не может быть.

    • clone() и malloc(), !*! nikolayshm, 04:08 , 15-Янв-12 (19)
      >> При этом когда они начиют конкурировать между собой, возникает deadlock в функциях
      >> malloc()/free()
      > Конечно возникает. Потому что память одного процесса неожиданно редактирует другой процесс.

      Так вопрос-то был соответствующий - почему так. malloc/free они ведь thread-safe :)

      > Если какой-то поток вызывает SIGSEGV - значит вся память испорчена. Общая, всего
      > процесса!!

      Кстати, это неправильное утверждение.
      SIGSEGV is the signal sent to a process when it makes an invalid memory reference, or segmentation fault.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру