Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вызов внешних программ

4.9K
24 марта 2007 года
efferson
57 / / 08.12.2005
Вобщем проблема заключается в следующеим: фунции семейства exec, как сказано в мануале заменяют образ текущего процесса новым образом (образом того приложения, которое они выхывают):
"The exec family of functions replaces the current process image with a new process image".
Отсюда вопрос: как вызвать внешнюю программу так, что бы текущий процесс продолжил своё выполнение?
502
25 марта 2007 года
Jail
550 / / 30.01.2007
Цитата:
Отсюда вопрос: как вызвать внешнюю программу так, что бы текущий процесс продолжил своё выполнение?


С помощью функции exec(), никак. Функция exec() (execute) загружает и запускает другую программу. Таким образом, новая программа полностью замещает текущий процесс. Новая программа начинает свое выполнение с функции main. Все файлы вызывающей программы остаются открытыми. Они также являются доступными новой программе. Используется шесть различных вариантов функций exec.

 
Код:
#include <unistd.h>
int execl(char *name, char *arg0, ... /*NULL*/);
int execv(char *name, char *argv[]);
int execle(char *name, char *arg0, ... /*,NULL,
           char *envp[]*/);
int execve(char *name, char *arv[], char *envp[]);
int execlp(char *name, char *arg0, ... /*NULL*/);
int execvp(char *name, char *argv[]);

Вызов exec происходит таким образом, что переданная в качестве аргумента программа загружается в память вместо старой, которая вызвала exec. Старой программе больше не доступны сегменты памяти, которые перезаписаны новой программой. Так что самой функцией этого не предусмотренно.
Но ....есть способ)) Можно создать новый процесс с помощью системного вызова fork(). Синтаксис вызова следующий:
 
Код:
#include <sys/types>
#include <unistd.h>
pid_t fork(void);

pid_t является примитивным типом данных, который определяет идентификатор процесса или группы процессов. При вызове fork() порождается новый процесс (процесс-потомок), который почти идентичен порождающему процессу-родителю. Процесс-потомок наследует следующие признаки родителя:
* сегменты кода, данных и стека программы;
* таблицу файлов, в которой находятся состояния флагов дескрипторов файла, указывающие, читается ли файл или пишется. Кроме того, в таблице файлов содержится текущая позиция указателя записи-чтения;
* рабочий и корневой каталоги;
* реальный и эффективный номер пользователя и номер группы;
* приоритеты процесса (администратор может изменить их через nice);
* контрольный терминал;
* маску сигналов;
* ограничения по ресурсам;
* сведения о среде выполнения;
* разделяемые сегменты памяти.
При вызове fork() возникают два полностью идентичных процесса. Весь код после fork() выполняется дважды, как в процессе-потомке, так и в процессе-родителе.
Пример порождения процесса через fork() :
Код:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
main()
{
  pid_t pid;
  int rv;
  switch(pid=fork()) {
  case -1:
          perror("fork"); /* произошла ошибка */
          exit(1); /*выход из родительского процесса*/
  case 0:
          printf(" CHILD: Это процесс-потомок!\n");
          printf(" CHILD: Мой PID -- %d\n", getpid());
          printf(" CHILD: PID моего родителя -- %d\n",
              getppid());
          printf(" CHILD: Введите мой код возврата
                         (как можно меньше):");
          scanf(" %d");
          printf(" CHILD: Выход!\n");
          exit(rv);
  default:
          printf("PARENT: Это процесс-родитель!\n");
          printf("PARENT: Мой PID -- %d\n", getpid());
          printf("PARENT: PID моего потомка %d\n",pid);
          printf("PARENT: Я жду, пока потомок
                          не вызовет exit()...\n");
          wait();
          printf("PARENT: Код возврата потомка:%d\n",
                   WEXITSTATUS(rv));
          printf("PARENT: Выход!\n");
  }
}

А так же------->>>>>>>
Код:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
   char pid{[}255{]};
   fork();
   fork();
   fork();
   sprintf(pid, "PID : %d\n",getpid());
   write(STDOUT_FILENO, pid, strlen(pid));
   exit(0);
}

В этом случае будет создано семь процессов-потомков. Первый вызов fork() создает первого потомка. Как указано выше, процесс наследует положение указателя команд от родительского процесса. Указатель команд содержит адрес следующего оператора программы. Это значит, что после первого вызова fork() указатель команд и родителя, и потомка находится перед вторым вызовом fork().После второго вызова fork() и родитель, и первый потомок производят потомков второго поколения - в результате образуется четыре процесса. После третьего вызова fork() каждый процесс производит своего потомка, увеличивая общее число процессов до восьми.
Ну вот и всё)) Думаю тебе немного нужно пересмотреть реализацию своей задачи, подход через exec() не верен! Удачи тебе прогер под Linux!!! ;)
4.9K
25 марта 2007 года
efferson
57 / / 08.12.2005
Спасиба, конечно, но execl у я и так из потомка вызывал :) Суть проблемы если вкратце в следующем: исходный процесс создаёт канал и порождает два одноранговых потомка. Первый потомок вызывает execl'ем команду ls -lisa и перенаправляет данные в канал. Во втором потомке стандартный файл ввода заменяется концом чтения канала и вызывается execl для команды grep. Всё бы хорошо, но в конце последовательности данных, идущих на вход команде grep должен быть сивол конца файла (CTRL + D). Вот я и годаю, как его туда запихнуть... :) В принципе можно вместо execl'a попробовать system... ,но как-то хочется решить проблему при помощи первого..
2
25 марта 2007 года
squirL
5.6K / / 13.08.2003
system - это и есть fork+exec
Цитата:

одноранговых потомка


это как? :-\

361
25 марта 2007 года
Odissey_
661 / / 19.09.2006
FILE * f = popen("ls -lisa","r");
if (f==NULL) exit;
char c;
while((c=fgetc(f))!= EOF)
cout<<c;
pclose(f);
непойдет?
502
25 марта 2007 года
Jail
550 / / 30.01.2007
Цитата:
Вот я и годаю, как его туда запихнуть... В принципе можно вместо execl'a попробовать system... ,но как-то хочется решить проблему при помощи первого..


С помощью execl не сможешь всё таки решить эту задачку)))

Цитата:
Цитата:
одноранговых потомка

это как? :-\


Это скорее от одного родителя :)

4.9K
26 марта 2007 года
efferson
57 / / 08.12.2005
Цитата:

[quote]Цитата:
одноранговых потомка



это как? :-\ Это скорее от одного родителя [/quote]
Угу - помоему в литературе это так называлось...

Вобщем решил проблему тем же способом, что и описывал во втором посте. Никакого символа конца там дописывать не надо, всё и так уже продумано - просто кривые руки :)))

Если кому интересно - ниже код:

Код:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

//-------------------------Global Variables--------------------------------
    extern int errno;
    bool signal_flag = false;
//-------------------------------------------------------------------------

//------------------------Auxilary functions-------------------------------
   
    void onSignal( int )
    {
    signal_flag = true;
    }
   
    void echo( const char* const message, pid_t pid )
    {
    fprintf( stderr, "(debug message) Process %d sent message: %s\n", pid, message );
    }
   
//-------------------------------------------------------------------------
    int main( int argc, char** argv )
    {
        //Declare Variables
        short int status, execute_status;
        pid_t process_ls, process_grep, process_wc, process_common;
        int pipeOne[ 2 ], pipeTwo [ 2 ], fp;
        char *grepArgument;
       
        //Declare Auxilary Variables
        unsigned short int i;
        int errCode;

        //Initialize Variables
        status = execute_status = 0;
        char fileName[] = "a.txt";
        errCode = 0;
       
        //If any argument exists set it as grep parameter
        if( argc > 1 )
            grepArgument = argv[1];
        else
        {
            grepArgument = (char*)malloc( strlen( "April" ) + 1 );
            strcpy( grepArgument, "April" );
        }

        //Set signal catcher
        signal( SIGUSR1, onSignal );

        //Creating pipes (one per pipeline)
        pipe( pipeOne );
        pipe( pipeTwo );

        //Creating childs. Let's each child get start after signal of preversion process (logical sequence)
        //-------------------------------------------------------------------------------------------------
       
        process_ls = fork();
        if( process_ls == (pid_t)0 )
        {
            //-----------------------Body of child process---------------------------
           
            //Print stats
            echo( "Started...", getpid() );
           
            //Set process output to pipeOne and close unusefull
            close( pipeOne[ 0 ] );
                close( pipeTwo[ 0 ] );
            close( pipeTwo[ 1 ] );         

            close( STDOUT_FILENO );
            dup( pipeOne[ 1 ] );
           
            //Call to external program. Result will be redirected to pipeOne
            errCode = execl( "/bin/ls", "ls", "-a", "-l", NULL );
            if( errCode == -1 )
            {
                echo( strerror( errno ), getpid() );
                kill( getppid(), SIGUSR1 );
                execute_status = -1;
            }
           
            exit( execute_status );    

            //-----------------------------------------------------------------------
        }  

        process_grep = fork();
        if( process_grep == (pid_t)0 )
        {
            //-----------------------Body of child process---------------------------
           
            //Print stats
            echo( "Started...", getpid() );
           
            //Set process input to pipeOne and process output to pipeTwo
            close( pipeOne[ 1 ] );
            close( pipeTwo[ 0 ] );
           
            close( STDIN_FILENO );
            dup( pipeOne[ 0 ] );
            close( STDOUT_FILENO );
            dup( pipeTwo[ 1 ] );

            //Call to external program. Result will be redirected to pipeTwo
            errCode = execl( "/bin/grep", "grep", grepArgument, NULL );
            if( errCode == -1 )
            {
                echo( strerror( errno ), getpid() );
                kill( getppid(), SIGUSR1 );
                execute_status = -1;
            }
           
            exit( execute_status );

            //-----------------------------------------------------------------------
        }
       
        process_wc = fork();
        if( process_wc == (pid_t)0 )
        {
            //-----------------------Body of child process--------------------------
           
            //Print stats
            echo( "Started...", getpid() );

            //Set process input to pipeTwo and output to file
            close( pipeOne[ 0 ] );
            close( pipeOne[ 1 ] );
                close( pipeTwo[ 1 ] );
           
            fp = open( fileName, O_WRONLY|O_CREAT );
           
            close( STDIN_FILENO );
            dup( pipeTwo[ 0 ] );
            close( STDOUT_FILENO );
            fcntl( fp, F_DUPFD, STDOUT_FILENO );

            //Call to external program. Result will be redirected to pipeTwo
            errCode = execl( "/usr/bin/wc", "wc", "-l", NULL );
            if( errCode == -1 )
            {
                echo( strerror( errno ), getpid() );
                kill( getppid(), SIGUSR1 );
                execute_status = -1;
            }
           
            exit( execute_status );

            //-----------------------------------------------------------------------
        }

        //-------------------------------------------------------------------------------------------------

        //Close all relations with pipes
        close( pipeOne[ 0 ] );
        close( pipeOne[ 1 ] );
        close( pipeTwo[ 0 ] );
        close( pipeTwo[ 1 ] );

        //Waiting for childs
        while( ( process_common = wait(&status) ) > 0 )
        {
            //If error occured atleast in one child - terminate all application
            if( signal_flag )
            {
                kill( -getpgrp(), SIGKILL );
                execute_status = -1;
            }
            else
                echo( "Finished...", process_common );
        }
       
        return( execute_status );
    }
502
26 марта 2007 года
Jail
550 / / 30.01.2007
Ну я тебе про чё и толковал, просто мы друг друга не поняли))) :D
Ты также созжаёшь одноранговых потомков с помощью fork(), а уж потом и вызываешь с помощью execl() самих ls и grep ))))) :)
4.9K
28 марта 2007 года
efferson
57 / / 08.12.2005
Бывает... :)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог