Ответ 1
В Linux daemon() - это то, что вы ищете, если я правильно вас понимаю.
Какой лучший способ для запуска запущенной программы C или С++ из командной строки поставить себя в фоновом режиме, что эквивалентно запуску пользователя из оболочки unix с помощью & в конце команды? (Но пользователь этого не сделал.) Это графическое приложение и не требует ввода/вывода оболочки, поэтому нет причин связывать оболочку после запуска. Но я хочу, чтобы запуск командной оболочки был автоматически настроен без "&". (или в Windows).
В идеале я хочу решение, которое будет работать на любых Linux, OS X и Windows. (Или отдельные решения, которые я могу выбрать с помощью #ifdef.) Достаточно предположить, что это должно быть сделано в самом начале выполнения, а не где-то посередине.
Одно из решений заключается в том, чтобы основная программа была script, которая запускает реальный двоичный файл, тщательно помещая его в фоновый режим. Но кажется неудовлетворяющим необходимость в этих связанных оболочках/двоичных парах.
Еще одно решение - немедленно запустить еще одну выполненную версию (с помощью "system" или "CreateProcess" ) с теми же аргументами командной строки, но поместив дочерний элемент в фоновый режим, а затем с родительским выходом. Но это кажется неуклюжим по сравнению с тем, что процесс ставит себя на задний план.
Отредактировано после нескольких ответов. Да, fork() (или system() или CreateProcess в Windows) является одним из способов сделать это, что я намекнул в своем первоначальном вопросе, Но все эти решения делают ВТОРОЙ процесс, который основан на предыстории, а затем завершают исходный процесс. Мне было интересно, есть ли способ перевести EXISTING в фоновый режим. Одно из отличий заключается в том, что если приложение было запущено из script, который записал свой идентификатор процесса (возможно, для последующего убийства или другой цели), новый разветвленный или созданный процесс будет иметь другой идентификатор и, следовательно, не будет контролироваться никаким запуском script, если вы видите, что я получаю.
Изменить # 2:
fork() не является хорошим решением для OS X, где man-страница для "fork" говорит, что это небезопасно, если используются определенные фреймворки или библиотеки. Я попробовал это, и мое приложение громко жалуется во время выполнения: "Процесс разветвлен, и вы не можете безопасно использовать эту функциональность CoreFoundation. Вы ДОЛЖНЫ exec()".
Меня заинтриговал daemon(), но когда я попробовал его в OS X, он дал то же сообщение об ошибке, поэтому я предполагаю, что это просто причудливая оболочка fork() и имеет те же ограничения.
Простите центризм OS X, это как раз и есть система передо мной на данный момент. Но я действительно ищу решение для всех трех платформ.
В Linux daemon() - это то, что вы ищете, если я правильно вас понимаю.
Мой совет: не делать этого, по крайней мере, не под Linux/UNIX.
Программы GUI в Linux/UNIX традиционно не автофонируют сами. Хотя иногда это может раздражать новичков, у него есть ряд преимуществ:
Легко фиксировать стандартную ошибку в случае дампов ядра/других проблем, требующих отладки.
Легко для оболочки script запускать программу и ждать, пока она не завершится.
Легко для оболочки script запускать программу в фоновом режиме и получать ее идентификатор процесса:
gui-program &
pid=$!
# do something with $pid later, such as check if the program is still running
Если ваша программа вилки сама по себе, это поведение сломается.
"Сценарий" полезен во многих непредвиденных обстоятельствах, даже с графическими программами, что я не решаюсь явно нарушать эти поведения.
Windows - это еще одна история. AFAIK, программы Windows автоматически запускаются в фоновом режиме - даже при вызове из командной оболочки - если они явно не запрашивают доступ к командному окну.
Как обычно это делается в Unix-подобных ОС, это fork() в начале и выход из родителя. Это не будет работать в Windows, но гораздо более элегантно, чем запуск другого процесса, в котором существует функция forking.
Три вещи нужно делать,
fork
setsid
redirect STDIN, STDOUT and STDERR to /dev/null
Это относится к системам POSIX (все те, о которых вы говорите, являются POSIX (но Windows останавливается на бите претензий))
В UNIX вам нужно развить в два раза подряд и дать родителям умереть.
Процесс не может оказаться в фоновом режиме, потому что это не тот, который отвечает за фон против переднего плана. Это будет оболочка, ожидающая выхода процесса. Если вы запускаете процесс с амперсандом "&" в конце, то оболочка не ждет выхода процесса.
Но единственный способ, с помощью которого процесс может выйти из оболочки, - это разблокировать другой дочерний элемент, а затем вернуть исходный исходный код обратно в ожидающую оболочку.
Из оболочки вы можете выполнить фоновый процесс с помощью Control-Z, затем введите "bg".
Фоновая обработка процесса - это функция оболочки, а не функция ОС.
Если вы хотите, чтобы приложение начиналось в фоновом режиме, типичным трюком является запись оболочки script, чтобы запустить ее, которая запускает ее в фоновом режиме.
#! /bin/sh
/path/to/myGuiApplication &
Чтобы следить за редактируемым вопросом:
Мне было интересно, есть ли способ перевести EXISTING в фоновый режим.
В Unix-подобной ОС действительно нет способа сделать это, о чем я знаю. Оболочка заблокирована, поскольку она выполняет один из вариантов вызова wait(), ожидая завершения дочернего процесса. Не существует способа для продолжения работы дочернего процесса, но каким-то образом заставить оболочку wait() возвращаться с статусом "please stop watch me". Причина, по которой у вас есть дочерняя вилка и выход из оригинала, - это значит, что оболочка вернется с wait().
Вот несколько псевдокодов для Linux/UNIX:
initialization_code()
if(failure) exit(1)
if( fork() > 0 ) exit(0)
setsid()
setup_signal_handlers()
for(fd=0; fd<NOFILE; fd++) close(fd)
open("/dev/null", O_RDONLY)
open("/dev/null", O_WRONLY)
open("/dev/null", o_WRONLY)
chdir("/")
И поздравления, ваша программа продолжается как независимый "демоннизированный" процесс без контрольного TTY и без каких-либо стандартных входов и выходов.
Теперь в Windows вы просто создаете свою программу как приложение Win32 с помощью WinMain() вместо main(), и она запускается без консоли автоматически. Если вы хотите работать как сервис, вам придется посмотреть, потому что я его никогда не писал, и я действительно не знаю, как они работают.
Вы отредактировали свой вопрос, но вам все еще может быть недостаток в том, что ваш вопрос является синтаксической ошибкой сортировки - если процесс не был помещен в фоновом режиме, и вы хотите, чтобы PID остался прежним, вы не можете игнорировать тот факт, что программа, которая начала процесс, ждет этого PID, и это в значительной степени определение на переднем плане.
Я думаю, вам нужно подумать о том, почему вы хотите, чтобы оба помещали что-то в фоновом режиме и сохраняли PID одинаково. Я предлагаю вам, вероятно, не нужно оба этих ограничения.
Как упоминалось выше, fork() - это как это сделать на * nix. Вы можете получить fork() в Windows, используя библиотеки MingW или Cygwin. Но вам потребуется перейти на использование GCC в качестве вашего компилятора.
В чистом мире Windows вы должны использовать CreateProcess (или один из его производных CreateProcessAsUser, CreateProcessWithLogonW).
Самый распространенный способ сделать это в Linux - это forking. То же самое должно работать на Mac, так как для Windows я не уверен на 100%, но я считаю, что у них что-то похожее.
В основном происходит процесс, который разбивается на два процесса, а затем исходный из них выходит (возвращая управление оболочке или что-то еще), а второй процесс продолжает работать в фоновом режиме.
Я не уверен в Windows, но в UNIX-подобных системах вы можете fork()
затем setsid()
разветвленный процесс переместить его в новую группу процессов, которая не подключена к терминалу.
Если вам нужен script, чтобы иметь PID программы, вы все равно можете получить его после вилки.
Когда вы используете fork, сохраните PID дочернего элемента в родительском процессе. Когда вы выходите из родительского процесса, выведите PID на STD{OUT,ERR}
или просто получите оператор return pid;
в конце main()
. Затем вызов script может получить pid программы, хотя для этого требуется определенное знание того, как работает программа.
Простейшей формой фона является:
if (fork() != 0) exit(0);
В Unix, если вы хотите полностью отделить от tty полностью, вы бы сделали:
0
, 1
и 2
).if (fork() != 0) exit(0);
setpgroup(0,getpid()); /* Might be necessary to prevent a SIGHUP on shell exit. */
signal(SIGHUP,SIG_IGN); /* just in case, same as using nohup to launch program. */
fd=open("/dev/tty",O_RDWR);
ioctl(fd,TIOCNOTTY,0); /* Disassociates from the terminal */
close(fd);
if (fork() != 0) exit(0); /* just for good measure */
Это должно полностью демонизировать вашу программу.
В Windows, я думаю, что закрывающая вещь, которую вы собираетесь использовать fork(), загружает вашу программу в качестве службы Windows.
Вот ссылка на статью об услугах Windows... CodeProject: простой пример службы Windows
Итак, как вы говорите, просто fork() ing не будет делать трюк. Что вы должны сделать, это fork(), а затем re-exec(), как это делает этот пример кода:
#include stdio.h>
#include <unistd.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
int main(int argc, char **argv)
{
int i, j;
for (i=1; i<argc; i++)
if (strcmp(argv[i], "--daemon") == 0)
{
for (j = i+1; j<argc; j++)
argv[j-1] = argv[j];
argv[argc - 1] = NULL;
if (fork()) return 0;
execv(argv[0], argv);
return 0;
}
sleep(1);
CFRunLoopRun();
CFStringRef hello = CFSTR("Hello, world!");
printf("str: %s\n", CFStringGetCStringPtr(hello, CFStringGetFastestEncoding(hello)));
return 0;
}
Цикл должен проверить аргумент --daemon, и если он присутствует, удалите его перед повторным выполнением, чтобы избежать бесконечного цикла.
Я не думаю, что это сработает, если двоичный код будет помещен в путь, потому что argv [0] не обязательно является полным путем, поэтому его нужно будет изменить.
/**Deamonize*/
pid_t pid;
pid = fork(); /**father makes a little deamon(son)*/
if(pid>0)
exit(0); /**father dies*/
while(1){
printf("Hello I'm your little deamon %d\n",pid); /**The child deamon goes on*/
sleep(1)
}
/** try 'nohup' in linux(usage: nohup <command> &) */
В Unix я научился делать это с помощью fork()
.
Если вы хотите перевести текущий процесс в фоновый режим, fork
он дважды.
Я пытался решить проблему.
От родительского процесса требуется только одна вилка.
Самое главное, что после fork родительский процесс должен умереть, вызывая _exit(0);
и NOT, вызывая exit(0);
Когда используется _exit(0);
, командная строка немедленно возвращается в оболочку.
Это трюк.