The OpenNET Project / Index page

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




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Треды + fork, !*! Petr, 27-Мрт-09, 01:54  [смотреть все]
Есть достаточно сложное многопотоковое приложение. Оно должно иногда запускать дочерние процессы и контролировать их выполнение. Возникает такая ситуация: по TCP этому приложению отправляется запрос, на который оно успешно fork'ает ребенка, отвечает `ok' и закрывает сокет. Проблема в том, что сокет не закрывается, по всей видимости из-за того, что при fork дескриптор сокета наследуется. Вопрос: как корректно закрыть все родительские дескрипторы в ребенке?

1. Вести учет открытых файловых дескрипторов по всему приложению я, разумеется, не собираюсь, по этой же причине никаких FD_CLOEXEC.
2. Нужно кроссплатформенное решение. Есть unshare, но это только Linux; есть rfork, но это только FreeBSD.

  • Треды + fork, !*! anonymous, 08:07 , 27-Мрт-09 (1)
    >[оверквотинг удален]
    >контролировать их выполнение. Возникает такая ситуация: по TCP этому приложению отправляется
    >запрос, на который оно успешно fork'ает ребенка, отвечает `ok' и закрывает
    >сокет. Проблема в том, что сокет не закрывается, по всей видимости
    >из-за того, что при fork дескриптор сокета наследуется. Вопрос: как корректно
    >закрыть все родительские дескрипторы в ребенке?
    >
    >1. Вести учет открытых файловых дескрипторов по всему приложению я, разумеется, не
    >собираюсь, по этой же причине никаких FD_CLOEXEC.
    >2. Нужно кроссплатформенное решение. Есть unshare, но это только Linux; есть rfork,
    >но это только FreeBSD.

    1. Есть shutdown()
    2. п. 1 не спасёт от небходимости закрывать дескриптор в parent --- иначе потекут дескрипторы, а это ограниченный ресурс.
    3. Аффтору убить себя ап стену.

    • Треды + fork, !*! const86, 11:19 , 27-Мрт-09 (2)
      >3. Аффтору убить себя ап стену.

      Зря вы так. С клиентским сокетом действительно всё просто: форкнулись, в родительском процессе закрыли, в дочернем общаемся с клиентом. Но есть интересный момент с другими файлами, которые могли наоткрываться в родительском процессе, особенно в других потоках. Они останутся в дочернем. Вроде как не особо и мешает это, но всё же лучше бы их тоже закрывать.

      • Треды + fork, !*! vic, 13:33 , 27-Мрт-09 (3)
        >>3. Аффтору убить себя ап стену.
        >
        >Зря вы так. С клиентским сокетом действительно всё просто: форкнулись, в родительском
        >процессе закрыли, в дочернем общаемся с клиентом. Но есть интересный момент
        >с другими файлами, которые могли наоткрываться в родительском процессе, особенно в
        >других потоках. Они останутся в дочернем. Вроде как не особо и
        >мешает это, но всё же лучше бы их тоже закрывать.

        Не зря :) автор же написал:
        >1. Вести учет открытых файловых дескрипторов по всему приложению я, разумеется, не
        >собираюсь, по этой же причине никаких FD_CLOEXEC.

        • Треды + fork, !*! Petr, 15:51 , 27-Мрт-09 (5)
          >Не зря :) автор же написал:
          >>1. Вести учет открытых файловых дескрипторов по всему приложению я, разумеется, не
          >>собираюсь, по этой же причине никаких FD_CLOEXEC.

          Вы что же, не согласны, что это угрёбищное решение? Хотя бы потому, что в проекте используются закрытые библитеки, которые файлы открывают, а вот впихнуть в них fcntl - звиняйте. Поэтому я просил решение, а не костыль.

          • Треды + fork, !*! vic, 16:29 , 27-Мрт-09 (7)
            >>Не зря :) автор же написал:
            >>>1. Вести учет открытых файловых дескрипторов по всему приложению я, разумеется, не
            >>>собираюсь, по этой же причине никаких FD_CLOEXEC.
            >
            >Вы что же, не согласны, что это угрёбищное решение? Хотя бы потому,
            >что в проекте используются закрытые библитеки, которые файлы открывают, а вот
            >впихнуть в них fcntl - звиняйте. Поэтому я просил решение, а
            >не костыль.

            Не следить за дескрипторами это и есть 'угрёбищное' решение.

            Использовать для всех управляемых дескрипторов флаг FD_CLOEXEC, это нормальное корректное решение. Ни разу не костыль.

            Для неуправляемых по какой-либо причине дескрипторов следует предпринять попытки сделать их управляемые и далее см. выше. Иначе возможно использование следующего приема:

            // в случае отсутствия getdtablesize() можно использовать макрос MAX_FD
            for (int i_fd = getdtablesize()-1;  i_fd > 2; --i_fd) close(i_fd); // оставили 0,1,2

            А также есть интересный для изучения каталог /proc/self/fd, но он может быть не везде.

            Прием никаким образом не спасает от неопределенного поведения модулей кода которые зависят от закрытых, в обход этих модулей, дескрипторов.

            Кросплатформенного решения в данном случае не может быть, слишком разные платформы, тем более никому не ясен ваш список ОС :)

            • Треды + fork, !*! Petr, 17:39 , 27-Мрт-09 (8)
              >Не следить за дескрипторами это и есть 'угрёбищное' решение.
              >
              >Использовать для всех управляемых дескрипторов флаг FD_CLOEXEC, это нормальное корректное решение. Ни
              >разу не костыль.

              Это именно костыль, потому закрывать или не закрывать дескрипторы при exec - это исключительно дело кода, вызывающего exec, а не кода, работающего с этими дескрипторами. Простой пример - после форка я могу exec'нуть как кусок себя, который ожидает открытый 3, так и стороннюю программу, где должно быть закрыто все. И что, cloexec или не cloexec?

              Про чужой код я уже упомянул - ваши `следует предпринять попытки' из области фантастики.
              Вы предлагаете лезть во _все_ компоненты, и втыкать туда fcntl, тогда как решение - закрывать или не закрывать, принимается все равно перед fork'ом или exec'ом.

              >// в случае отсутствия getdtablesize() можно использовать макрос MAX_FD
              >for (int i_fd = getdtablesize()-1;  i_fd > 2; --i_fd) close(i_fd); // оставили 0,1,2

              Да, мне это по началу казалось костылем, но, видимо, так оно и делается.

              В man close, оказывается, написано кое-что по этому поводу, а также про cloexec. В кратце - закрывайте close'ом, а если нужно закрыть при exec'е, но оставить, если exec обломится, юзайте FD_CLOEXEC.

    • Треды + fork, !*! Petr, 15:43 , 27-Мрт-09 (4)
      >1. Есть shutdown()
      >2. п. 1 не спасёт от небходимости закрывать дескриптор в parent ---
      >иначе потекут дескрипторы, а это ограниченный ресурс.

      shutdown не то. Нужно _закрыть_ в ребенке все, кроме 0,1,2. TCP соединение обрабатывается  в родителе, в котором все, что нужно, закрывается.

      >3. Аффтору убить себя ап стену.

      Детский сад...

      • Треды + fork, !*! const86, 16:09 , 27-Мрт-09 (6)
        > Нужно _закрыть_ в ребенке все, кроме 0,1,2.

        Можно посмотреть свой RLIMIT_NOFILE и пробежаться в цикле, всё поcloseить.
        Смутно припоминается, что это как-то вроде можно побыстрее сделать, но не могу вспомнить.

      • Треды + fork, !*! svn, 23:08 , 27-Мрт-09 (9)
        >shutdown не то. Нужно _закрыть_ в ребенке все, кроме 0,1,2.

        Закрой в себе сначала всё плохое и ненужное, а потом делай детей.

        • Треды + fork, !*! Аноним, 17:35 , 29-Мрт-09 (10)
          >Закрой в себе сначала всё плохое и ненужное, а потом делай детей.

          Универсальный ответ. Напиши его во все темы на этом форуме и застрелись, идиот :))




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

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