Недавно я наткнулся на реализацию popen() (та же идея, другой API) с использованием clone(2), где я открыл issue с запросом использования vfork(2) или posix_spawn() в целях лучшей переносимости на другие платформы. Оказывается, для Linux есть одно очень важное преимущество в использовании clone(2). И вот я думаю, что мне следует раскрыть тему, которую я там затронул, где-нибудь еще: в гисте, в блоге, да где угодно.
Итак, начнем.
Давным-давно я, как и многие фанаты Unix, думал, что fork(2) и модель порождения процессов fork-exec были лучшим решением в мире, а Windows нервно курил в сторонке, имея только exec*() и _spawn*(), последний из которых был чистым виндоусизмом.
После многих лет практики я пришел к выводу, что fork(2) на самом деле является злом. А vfork(2)
, долгое время считавшийся злом, на самом деле является добром. Изящная вариация vfork(2)
, которая избегает необходимости блокировать родителя, была бы даже лучше (об этом чуть позже).
Такие серьезные заявки требуют объяснений, поэтому позвольте мне объяснить все по порядку.
Я не буду утруждать себя объяснением, что такое fork(2) - если вы это читаете, я полагаю, вы уже знаете. Но я расскажу про vfork(2)
и почему он считается опасным. vfork(2)
очень похож на fork(2)
, но новый процесс, который он создает, запускается в том же адресном пространстве, что и родительский, как если бы он был потоком. Он даже разделяет тот же стек с потоком, который вызвал vfork(2)
! Два потока не могут совместно использовать стек, поэтому родительский процесс останавливается до момента, когда дочерний выполнит свою задачу: либо exec*(2)
, либо _exit(2)
.