Как передать каналы и другие значения через параметры командной строки в C? - PullRequest
4 голосов
/ 08 мая 2011

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

int sem_id = semget (key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
if (pipe (pipe1)){
    printf("Error: %s",strerror(errno));
    exit(1);
}

if(execl("/home/tropix/program-3","/home/tropix/program-3", sem_id, shmid, pipe1, (char*)0) == 0){
    fprintf(stderr, "File Execution of program 3 failed.\n");
    exit(1);
}

Программа 3 не выполняется, поэтому у меня очевидно проблема с моим оператором execl. Если я удаляю переменные sem_id, shmid и pipe2, он запускается.

Спасибо за любые предложения.

Редактировать: добавлены операторы для создания shmid и sem_id. Я могу напечатать эти int в stdout, так что я уверен, что они имеют значение. А чтобы узнать, выполняется ли программа 3, см. Программу 3:

main(int argc, char *argv[]){
    int x;
    printf("Number of args = %d", argc);
    for(x=0;x<argc;x++){
    printf("arg#: %d, %s\n",x,argv[x]);
    }
}

Еще одно примечание: я скомпилировал программу 3. Если я удаляю аргументы execl и заменяю их словами в кавычках («test»), они отображаются в качестве аргументов на дочерней странице. Но в этом случае НИЧЕГО не печатает из программы 3.

Ответы [ 3 ]

2 голосов
/ 08 мая 2011

Все аргументы программы должны быть строками.

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

Ваш код не показывает 'pipe2' ... Я предположил, что это был простой int, но еслиэто был массив (например, pipe1 is), тогда вам нужно добавить его в 0 или 1, чтобы получить соответствующий дескриптор файла:

char shmarg[20];
char semarg[20];
char piparg[20];
int semid = semget (key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
const char *cmd = "/home/tropix/program-3";

if (pipe(pipe1))
{
    printf("Failed to create pipe: %s\n", strerror(errno));
    exit(1);
}

snprintf(shmarg, sizeof(shmarg), "%d", shmid);
snprintf(semarg, sizeof(semarg), "%d", semid);
snprintf(piparg, sizeof(piparg), "%d", pipe2);

execl(cmd, cmd, semarg, shmarg, piparg, (char*)0);
fprintf(stderr, "File Execution of program 3 failed.\n");
exit(1);

Непонятно, почему вы создали pipe1;вам нужно сделать соответствующую сантехнику с ним.Если execl() возвращается, это не удалось.Вам не нужно проверять его возвращаемое значение.


Из комментариев:

[Я] просто вырезать соответствующие разделы для простоты [...] [Я] не уверен, что ты имеешь в виду под «подходящей сантехникой» с pipe1?Можете ли вы сказать мне, как это должно быть сделано, или передать мне некоторую информацию о том, как я могу инициализировать канал и передать его в следующий файл?Я понимаю, что создание канала в программе, которая требует его, может быть лучшим вариантом, но в этом случае его инициализация в программе 1 является обязательным требованием.

Простота в вопросе - хорошая идея ...

Я предполагаю, что между вызовом pipe() и execl() был fork(), который был пропущен.В противном случае pipe() не имеет никакого смысла.

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

Итак, ваш исправленный код может быть (пустые строки удалены, чтобы избежать полосы прокрутки):

char shmarg[20];
char semarg[20];
char piparg[20];
int semid = semget(key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
const char *cmd = "/home/tropix/program-3";
if (pipe(pipe1))
{
    printf("Failed to create pipe: %s\n", strerror(errno));
    exit(1);
}
pid_t pid = fork();
if (pid < 0)
    err_exit("Failed to fork");
else if (pid > 0)
{
    /* Do parental things */
    close(pipe1[0]);
    ...write to pipe1[1]...
}
else
{
    /* Do childish things */
    /* Assuming child is reading from pipe */
    close(pipe1[1]);
    snprintf(shmarg, sizeof(shmarg), "%d", shmid);
    snprintf(semarg, sizeof(semarg), "%d", semid);
    snprintf(piparg, sizeof(piparg), "%d", pipe1[0]);
    execl(cmd, cmd, semarg, shmarg, piparg, (char*)0);
    fprintf(stderr, "File Execution of program 3 failed.\n");
    exit(1);
}

Ясно, что если канал читается родителем и записывается дочерним, вам нужно жонглировать замыканиями и указаннымномер дескриптора файла.

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

0 голосов
/ 08 мая 2011

Откуда вы знаете, что program-3 не работает?Вызов execl выглядит нормально при условии, что /home/tropix/program-3 - исполняемая программа.Не могли бы вы предоставить определения для sem_id, shmid и pipe2?

0 голосов
/ 08 мая 2011

Я собираюсь предположить, что sem_id, shmid и pipe2 не являются строкой с нулевым символом в конце.Вам придется преобразовать их в то, что они являются аргументами команды, так же, как и в командной строке.

...