LINUX.ORG.RU

Запуск и ожидание дочерней программы

 ,


0

1

Нужно запустить дочерний процесс и дождаться от него данных. Ну например, командную строку, с командой ping , и получить результат. Есть такие вопросы: 1. Как это правильно делать в линукс? На винде будет CreateProcess / CreateThread, а тут как? fork , и в нем if (проверка дочерний или родительский процесс). Или потоки - как понял, потоки в линуксах не особо котируются?

2. Как дождаться всех данных от программы? Допустим

char buf[1024] = { 0 };

	FILE *p = popen("ping ya.ru -c 3", "r");

	if (p)
	{
		fread(buf, 1, 1024, p);
		puts(buf);
	}

	pclose(p);
Заблокирует ли fread поток до чтения всех данных или нет? Т.к. какой-то ls вернет результат сразу, а ping надо ждать.

3. Правильный ли подход код выше, или лучше создавать pipe ? Можно ли передать handle от pipe в другую программу (не в свою, где fork , а именно вот в левую, типа bash ? ) чтобы ответ пришел туда, а не в STDOUT.

fork , и в нем if (проверка дочерний или родительский процесс).

Да. В потомке вызываешь execve() нужной программы, ну или, если попроще, то system() + exit().

Или потоки - как понял, потоки в линуксах не особо котируются?

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

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
вместо attr ставишь NULL если не хочешь вникать или оно не нужно.

Заблокирует ли fread поток до чтения всех данных или нет?

Заблокирует до чтения хоть каких-то данных. Нужно делать цикл, ну и проверять feof() / ferror().

Правильный ли подход код выше, или лучше создавать pipe

popen() это pipe() + fork() + execve() + fdopen()

Можно ли передать handle от pipe в другую программу (не в свою, где fork , а именно вот в левую, типа bash

Можно в любую которую ты сам запустишь после этого как у тебя уже есть этот пайп. Чуть сложнее - можно в любую, которая рассчитана на то чтобы этот пайп у тебя принять (ищи SCM_RIGHTS, но вообще забей, тебе это не нужно пока). Ещё сложнее - можно вообще в любую, через инструменты отладки (но это тебе тоже не нужно).

firkax ★★★★★
()
Ответ на: комментарий от firkax

Спасибо! Еще одно - а если нужно выполнить 2-3 команды, с интервалом; как правильнее сделать? Например ls , потом wget какой-то, потом снова ls. Три раза system() , а потом exit (), да?

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

zer0cat
() автор топика

там унутре много подводных камней. Если на лабе препод не требует иного, используйте готовые классы и библиотеки.

к озвученному выше, как минимум надо ещё и сигналы, просто чтобы не валиться внезапно и не виснуть вдруг. А желательно ещё и env, пути и права, хотя-бы для культурки.

MKuznetsov ★★★★★
()
Ответ на: комментарий от zer0cat

Спасибо! Еще одно - а если нужно выполнить 2-3 команды, с интервалом; как правильнее сделать? Например ls , потом wget какой-то, потом снова ls. Три раза system() , а потом exit (), да?

Так можно, да. Но учти: system() это fork() + execve(«/bin/sh», ...) + wait(), и если тебе надо именно «выполнить sh-команду + подождать её завершения» (как это делают все шелл-скрипты) - то system() идеально подходит, если же надо что-то посложнее, то лучше делать всё самостоятельно через fork() итд, добавляя в нужные места свою логику.

По винде - потоки удобны тем, что разделяют глобальные переменные

А ещё глобальные переменные разделяют две по очереди вызванные функции в одном и том же потоке. Делать это именно в разных потоках в большинстве случаев оказывается не нужно. Нужно только в двух ситуациях:

1) тебе не хватает мощности одного процессорного ядра, хочешь второе итд (один поток - только одно ядро использует);

2) ты используешь системные функции, которые что-то долго делают (например, чтение файлов с лагающего диска с помощью read()), но при этом не хочешь на это время чтобы твоя программа зависала - тогда в одном потоке вызываешь системную функцию, а в другом - что-то другое что хочешь делать пока она висит;

firkax ★★★★★
()

я создаю pipe, вполне рабочее

    char buffer[256] = {0};
    std::string result;

    std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
    if(!pipe) throw std::runtime_error("error popen");

    while(!std::feof(pipe.get()))
    {
        if(std::fgets(buffer, sizeof(buffer), pipe.get()))
            result.append(buffer);
    }
anonymous2 ★★★★★
()
Последнее исправление: anonymous2 (всего исправлений: 2)