Подтвердить что ты не робот

Когда clone() и fork лучше, чем pthreads?

Я начинаю в этой области.

Я изучил fork(), vfork(), clone() и pthreads.

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

Но когда fork() и clone() лучше, чем pthreads? Не могли бы вы объяснить это мне, представив пример реального мира?

Спасибо в Advance.

4b9b3361

Ответ 1

Сила и слабость fork (и компании) заключается в том, что они создают новый процесс, который является клоном существующего процесса.

Это слабость, потому что, как вы указали, создание нового процесса имеет довольно много накладных расходов. Это также означает, что связь между процессами должна выполняться через некоторый "одобренный" канал (каналы, сокеты, файлы, область разделяемой памяти и т.д.).

Это сила, потому что она обеспечивает (большую) большую изоляцию между родителем и ребенком. Если, например, происходит сбой дочернего процесса, вы можете его убить и начать довольно легко. В отличие от этого, если дочерний поток умирает, убийство в лучшем случае проблематично - невозможно понять, какие ресурсы занимают только потоки, поэтому вы не можете их очистить. Аналогичным образом, поскольку все потоки процесса имеют общее адресное пространство, один поток, столкнувшийся с проблемой, может перезаписать данные, используемые всеми другими потоками, поэтому просто убить этот поток не обязательно будет достаточно, чтобы очистить беспорядок.

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

Что касается конкретных примеров, Apache может быть довольно хорошим. Он будет использовать несколько потоков для каждого процесса, но чтобы ограничить ущерб в случае проблем (между прочим), он ограничивает количество потоков для каждого процесса и может/будет порождать несколько отдельных процессов, работающих одновременно. На достойном сервере у вас может быть, например, 8 процессов с 8 потоками. Большое количество потоков помогает обслуживать большое количество клиентов в основном задании, связанном с вводом-выводом, и разбивать его на процессы означает, что если проблема возникает, она не становится внезапно полностью невосприимчивой и может закрыться и перезапустить процесс, не теряя много.

Ответ 2

clone (2) - это конкретный Linux syscall в основном используется для реализации потоков (в частности, используется для pthread_create). С помощью различных аргументов clone может также иметь fork (2) -подобное поведение. Очень немногие люди напрямую используют clone, использование библиотеки pthread более переносимо. Вероятно, вам нужно напрямую вызвать clone(2) syscall только в том случае, если вы реализуете свою собственную библиотеку потоков - конкурента Posix-threads - и это очень сложно (в частности, поскольку для блокировки может потребоваться использование futex (2) syscall в машинных настройках, закодированных в сборе, см. futex (7)), Вы не хотите напрямую использовать clone или futex, потому что pthreads гораздо проще использовать.

(Другие функции pthread требуют, чтобы в течение clone во время pthread_create) внутри libpthread.so выполнялось некоторое ведение бухгалтерского учета внутри libpthread.so)

Как ответил Jonathon, процессы имеют собственное адресное пространство и набор дескрипторов файлов. И процесс может выполнить новую исполняемую программу с помощью execve syscall, которые в основном инициализируют адресное пространство, стек и регистры для запуска нового (но файловые дескрипторы могут храниться, если только не использовать флажок close-on-exec, например thru O_CLOEXEC для open).

В Unix-подобных системах все процессы (за исключением самого первого процесса, обычно init, pid 1) создаются с помощью fork (или таких вариантов, как vfork; вы можете, но не хотите, используйте clone таким образом, чтобы он вел себя как fork).

(технически, в Linux есть несколько странных исключений, которые вы можете игнорировать, особенно процессы или потоки ядра, а также некоторые редкие инициированные ядрами процессы, такие как /sbin/hotplug....)

Секунды fork и execve являются центральными для создания процесса Unix (waitpid и связанных с ним системных вызовов).

Многопоточный процесс имеет несколько потоков (обычно созданных pthread_create), которые используют одно и то же адресное пространство и дескрипторы файлов. Вы используете потоки, когда хотите работать параллельно на одних и тех же данных в одном и том же адресном пространстве, но тогда вы должны заботиться о синхронизации и блокировке. Подробнее читайте учебник pthread.

Я предлагаю вам прочитать хорошую книгу программирования Unix, например Advanced Unix Programming и/или (свободно доступный) Расширенное программирование Linux

Ответ 3

Это совершенно разные вещи. fork() создает новый process. pthread_create() создает новый поток, который выполняется в контексте одного и того же процесса.

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

Процессы (по существу) полностью отделены друг от друга и не могут изменять друг друга.

Вы должны прочитать этот вопрос:


Как пример, если я являюсь вашей оболочкой (например, bash), когда вы вводите команду типа ls, я собираюсь fork() создать новый процесс, а затем exec() ls исполняемый файл. (И тогда я wait() для дочернего процесса, но это выходит из области.) Это происходит во всем другом адресном пространстве, и если ls взорвется, мне все равно, потому что я все еще выполняю свои собственный процесс.

С другой стороны, скажем, что я математическая программа, и меня попросили умножить две матрицы 100x100. Мы знаем, что матричное умножение является проблемой Embarrassingly Parallel. Итак, у меня есть матрицы в памяти. Я создаю N потоков, каждый из которых работает на одних и тех же исходных матрицах, помещая их результаты в соответствующее место в матрице результатов. Помните, что они работают в контексте одного и того же процесса, поэтому мне нужно убедиться, что они не копируют друг на друга данные. Если N равно 8, и у меня есть восьмиъядерный процессор, я могу эффективно вычислить каждую часть матрицы одновременно.

Ответ 4

Механизм создания процесса в unix с использованием fork() (и семейства) очень эффективен. Более того, большинство систем unix не поддерживают потоки уровня ядра. Этот поток не является сущностью, распознаваемой ядром. Следовательно, поток на такой системе не может получить преимущества планирования процессора на уровне ядра. библиотека pthread делает то, что не является kerenl, а скорее процессом. Также на такой системе pthreads реализуются с использованием vfork() и только в виде легкого веса. Поэтому использование потоковой передачи не имеет смысла, кроме переносимости в такой системе.

В соответствии с моим пониманием Sun-solaris и windows имеют поток уровня ядра, а семейство linux не поддерживает потоки ядра.

с процессами pipe и unix doamin сокеты очень эффективны IPC без проблем синхронизации. Я надеюсь, что это очистит, почему и когда нить должна использоваться практически.