Как программа на 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 ]

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

Как уже упоминалось, fork () - это то, как это сделать на * nix. Вы можете получить fork () в Windows, используя библиотеки MingW или Cygwin. Но для этого потребуется переключиться на использование GCC в качестве компилятора.

В чистом мире Windows вы должны использовать CreateProcess (или один из его производных CreateProcessAsUser, CreateProcessWithLogonW).

0 голосов
/ 24 марта 2010

Я пытался найти решение.

Требуется только одна ветвь от родительского процесса.

Наиболее важным моментом является то, что после форка родительский процесс должен умереть, вызвав _exit(0);, а НЕ вызвав exit(0);

Когда используется _exit(0);, командная строка немедленно возвращается на оболочку.

Это хитрость.

0 голосов
/ 23 февраля 2009

В Unix я научился делать это, используя fork(). Если вы хотите перевести запущенный процесс в фоновый режим, fork дважды.

0 голосов
/ 29 ноября 2008
/**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> &) */
0 голосов
/ 23 сентября 2008

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

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

Я не уверен насчет Windows, но в UNIX-подобных системах вы можете fork(), а затем setsid() раздвоенный процесс, чтобы переместить его в новую группу процессов, не подключенную к терминалу.

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

Под Windows закрытие, которое вы собираетесь получить в fork (), это загрузка вашей программы как службы Windows, я думаю.

Вот ссылка на вступительную статью о службах Windows ... CodeProject: простой пример службы Windows

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

Самый распространенный способ сделать это в Linux - через разветвление . То же самое должно работать на Mac, так как для Windows я не уверен на 100%, но я считаю, что у них есть что-то похожее.

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

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

Самая простая форма фона:

if (fork() != 0) exit(0);

В Unix, если вы хотите полностью удалить фоновую связь с tty, вы должны сделать:

  1. Закройте все дескрипторы, которые могут обращаться к tty (обычно 0, 1 и 2).
  2. if (fork() != 0) exit(0);
  3. setpgroup(0,getpid()); /* Might be necessary to prevent a SIGHUP on shell exit. */
  4. signal(SIGHUP,SIG_IGN); /* just in case, same as using nohup to launch program. */
  5. fd=open("/dev/tty",O_RDWR);
  6. ioctl(fd,TIOCNOTTY,0); /* Disassociates from the terminal */
  7. close(fd);
  8. if (fork() != 0) exit(0); /* just for good measure */

Это должно полностью демонизировать вашу программу.

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

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

Когда вы разветвляетесь, сохраните PID дочернего процесса в родительском процессе. Когда вы выходите из родительского процесса, либо выводите PID в STD{OUT,ERR}, либо просто используйте оператор return pid; в конце main(). Вызывающий сценарий может затем получить pid программы, хотя он требует определенных знаний о том, как работает программа.

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