Как программа на C / C ++ может оказаться в фоновом режиме? - PullRequest
14 голосов
/ 22 сентября 2008

Каков наилучший способ для запущенной программы на C или C ++, которая была запущена из командной строки, поместить себя в фоновый режим, что эквивалентно тому, если пользователь запустил из оболочки unix с '&' в конце команды? (Но пользователь этого не сделал.) Это приложение с графическим интерфейсом и не требует ввода-вывода в оболочку, поэтому нет причин связывать оболочку после запуска. Но я хочу, чтобы запуск команды оболочки был автоматически задан без '&' (или в Windows).

В идеале мне нужно решение, которое бы работало на любом из Linux, OS X и Windows. (Или отдельные решения, которые я могу выбрать с помощью #ifdef.) Можно предположить, что это должно быть сделано в самом начале выполнения, а не где-то посередине.

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

Другим решением является немедленный запуск другой исполняемой версии (с 'system' или CreateProcess) с теми же аргументами командной строки, но с помещением дочернего элемента в фоновом режиме и последующим родительским выходом. Но это кажется неуклюжим по сравнению с процессом, помещающим сам в фоновый режим.

Отредактировано после нескольких ответов : Да, fork () (или system (), или CreateProcess в Windows) - это один из способов сделать это, на что я намекал в своем первоначальном вопросе. Но все эти решения делают ВТОРОЙ процесс, который является фоновым, а затем завершают исходный процесс. Мне было интересно, есть ли способ отложить СУЩЕСТВУЮЩИЙ процесс на задний план. Одно из отличий состоит в том, что если приложение было запущено из сценария, в котором записан его идентификатор процесса (возможно, для последующего уничтожения или для других целей), вновь созданный или созданный процесс будет иметь другой идентификатор и, следовательно, не будет управляться каким-либо запускающим сценарием, если ты видишь, к чему я клоню.

Редактировать # 2 :

fork () не является хорошим решением для OS X, где на странице man для 'fork' сказано, что небезопасно использование определенных сред или библиотек. Я попробовал это, и мое приложение громко жалуется во время выполнения: «Процесс разорван, и вы не можете безопасно использовать эту функциональность CoreFoundation. Вы ДОЛЖНЫ выполнить exec ()».

Я был заинтригован daemon (), но когда я попробовал его на OS X, он выдал то же сообщение об ошибке, поэтому я предполагаю, что это просто необычная оболочка для fork () и имеет те же ограничения.

Извините за центризм OS X, просто сейчас передо мной стоит система. Но я действительно ищу решение для всех трех платформ.

Ответы [ 20 ]

10 голосов
/ 23 сентября 2008

Мой совет: не делайте этого , по крайней мере, не в Linux / UNIX.

Программы с графическим интерфейсом в Linux / UNIX традиционно не сами создают фоновый режим. Хотя это может иногда раздражать новичков, оно имеет ряд преимуществ:

  • Упрощает сбор стандартной ошибки в случае дампов ядра или других проблем, требующих отладки.

  • Позволяет сценарию оболочки запускать программу и ждать, пока она не будет завершена.

  • Облегчает работу сценария оболочки в фоновом режиме и получает идентификатор процесса:

    gui-program &
    pid=$!
    # do something with $pid later, such as check if the program is still running
    

    Если ваша программа разветвляется, это поведение прекратится.

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

Windows - это другая история. AFAIK, программы Windows автоматически запускаются в фоновом режиме - даже при вызове из командной оболочки - если они явно не запрашивают доступ к командному окну.

9 голосов
/ 23 сентября 2008

В Linux daemon () - это то, что вы ищете, если я вас правильно понимаю.

7 голосов
/ 22 сентября 2008

Способ, который обычно делается в Unix-подобных ОС - это fork () в начале и выход из родительского. Это не будет работать в Windows, но гораздо более элегантно, чем запуск другого процесса, в котором существует разветвление.

5 голосов
/ 22 сентября 2008

Три вещи нужно сделать,

fork
setsid
redirect STDIN, STDOUT and STDERR to /dev/null

Это относится к системам POSIX (все те, о которых вы упоминаете, называют POSIX (но Windows останавливается на бите запроса))

4 голосов
/ 22 сентября 2008

В UNIX вам нужно дважды разветвляться подряд и позволить родителю умереть.

4 голосов
/ 22 сентября 2008

Процесс не может поставить себя на задний план, потому что он не отвечает за фон против переднего плана. Это будет оболочка, которая ожидает выхода из процесса. Если вы запускаете процесс с амперсандом «&» в конце, то оболочка не ожидает завершения процесса.

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

Из оболочки вы можете создать фоновый процесс с помощью Control-Z, а затем набрать «bg».

3 голосов
/ 22 сентября 2008

Фоновая обработка процесса - это функция оболочки, а не функция ОС.

Если вы хотите, чтобы приложение запускалось в фоновом режиме, типичным приемом является написание сценария оболочки, запускающего его в фоновом режиме.

#! /bin/sh
/path/to/myGuiApplication &
2 голосов
/ 23 сентября 2008

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

Я думаю, вам нужно подумать о том, почему вы хотите поместить что-то на задний план и сохранить PID одинаковым. Я полагаю, вам, вероятно, не нужны оба этих ограничения.

2 голосов
/ 22 сентября 2008

Вот некоторый псевдокод для 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 (), и она автоматически запускается без консоли. Если вы хотите работать как служба, вам придется поискать это, потому что я никогда не писал ни одной, и я действительно не знаю, как они работают.

2 голосов
/ 22 сентября 2008

Чтобы ответить на ваш отредактированный вопрос:

Мне было интересно, есть ли способ поместить СУЩЕСТВУЮЩИЙ процесс в фоновый режим.

В Unix-подобных ОС действительно нет способа сделать это, о чем я знаю. Оболочка заблокирована, потому что она выполняет один из вариантов вызова wait (), ожидая завершения дочернего процесса. Невозможно, чтобы дочерний процесс продолжал выполняться, но каким-то образом заставил оболочку wait () вернуться со статусом «пожалуйста, прекратите наблюдать за мной». Причина, по которой у вас есть дочерняя вилка и выход из оригинала, заключается в том, что оболочка вернется из wait ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...