struct utmp record; // структура для записи данных из utmp
struct utmp record2;// она же, но для чтения из межпроцессного канала
int utmpfd; //fd для utmp
int reclen=sizeof(struct utmp); //значение len для read()
int fd[2];// массив указателей для pipe
pid_t childpid;// pid для процесса потомка
if((utmpfd=open(UTMP_FILE,O_RDONLY))==-1) //открываю файл utmp
{
perror(UTMP_FILE);
exit(1);
}
pipe(fd); //создание межпроцессного канала
Не получается передать данные по межпроцессному каналу
Программа выдачи списка всех пользователей, работающих в настоящее время в системе. Передать полученную информацию через межпроцессный канал в параллельный процесс, где вывести на экран.
Проблема в том что передача по каналу происходит в цикле, т.к. не обходимо обновлять передоваемые данные (обновляются в кажой итерации, пока не исчерпается файл utmp).
Объявляю переменные, открываю файл utmp с информацией о пользователях и создаю межпроцессный канал:
Код:
Далее непосредственно процесс передачи в параллельный процесс:
Код:
while(read(utmpfd,&record,reclen)==reclen)// так как записей в utmp обычно несколько, то нужен цикл, для прогона по всему файлу
{
if((childpid = fork()) == -1) //раcпараллеливание процесса и проверка на ошибки
{
perror("fork");
exit(1);
}
if(childpid == 0) //процесс потомок
{
close(fd[0]); //закрытие межпроцессного канала на чтение
write (fd[1], &record, sizeof(struct utmp)); //передаю информацию
exit(0);
}
else //процесс родитель
{
close(fd[1]); //закрытие межпроцессного канала на запись
read (fd[0], &record2, sizeof(struct utmp));
printf("\n%-8.8s ",record2.ut_name);
printf("%-8.8s ",record2.ut_line);
}
}
{
if((childpid = fork()) == -1) //раcпараллеливание процесса и проверка на ошибки
{
perror("fork");
exit(1);
}
if(childpid == 0) //процесс потомок
{
close(fd[0]); //закрытие межпроцессного канала на чтение
write (fd[1], &record, sizeof(struct utmp)); //передаю информацию
exit(0);
}
else //процесс родитель
{
close(fd[1]); //закрытие межпроцессного канала на запись
read (fd[0], &record2, sizeof(struct utmp));
printf("\n%-8.8s ",record2.ut_name);
printf("%-8.8s ",record2.ut_line);
}
}
Проблема в том, что результат печати выглядит следующим образом:
Код:
reboot ~
reboot ~
reboot ~
...
reboot ~
reboot ~
...
И так n-раз, ну не больше 8 обычно, по кличеству терминалов в системе.
Дело в том, что во время чтения процессом-предком из межпроцессного канала, информация считывается только в первой итерации цикла. То есть результат будет всегда одним и тем же.
Отсюда вопросы:
- прав ли я, что проблема именно в этом?
- если прав то как мне почистить заполненый канал, что бы в каждой итерации информация считывалась?
- если не прав, то что тогда здесь происходит? Почему в последующих итерациях значения структуры recor2 не обновляются?
UPD: вставил код печати структуры в процесс потомок, из него всё работает, то есть цикл while всё делает верно
Код:
if(childpid == 0) //процесс потомок
{
close(fd[0]); //закрытие межпроцессного канала на чтение
write (fd[1], &record, sizeof(struct utmp)); //передаю информацию
exit(0);
printf("\n%-8.8s ",record2.ut_name);
printf("%-8.8s ",record2.ut_line);
}
===========
результат:
reboot ~
runlevel ~
LOGIN tty4
LOGIN tty5
LOGIN tty2
LOGIN tty3
LOGIN tty6
LOGIN tty1
user tty7
user pts/0
{
close(fd[0]); //закрытие межпроцессного канала на чтение
write (fd[1], &record, sizeof(struct utmp)); //передаю информацию
exit(0);
printf("\n%-8.8s ",record2.ut_name);
printf("%-8.8s ",record2.ut_line);
}
===========
результат:
reboot ~
runlevel ~
LOGIN tty4
LOGIN tty5
LOGIN tty2
LOGIN tty3
LOGIN tty6
LOGIN tty1
user tty7
user pts/0
Код целиком:
Код:
#include <stdio.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
struct utmp record; // структура для запеси данных из utmp
struct utmp record2;// она же но для записи из межпроцессного канала
int utmpfd; //fd для utmp
int reclen=sizeof(struct utmp); //значение len для read()
int fd[2];
int filefd;
pid_t childpid;
if((utmpfd=open(UTMP_FILE,O_RDONLY))==-1){ //открываем файл utmp
perror(UTMP_FILE);
exit(1);
}
pipe(fd); //создание межпроцессного канала
while(read(utmpfd,&record,reclen)==reclen)
{
if((childpid = fork()) == -1) //проверка на ошибки
{
perror("fork");
exit(1);
}
if(childpid == 0) //процесс потомок
{
close(fd[0]); //закрытие межпроцессного канала на чтение
write (fd[1], &record, sizeof(struct utmp));
printf("\nrec1 - %-8.8s ",record.ut_name); //проверю считывается ли при каждой итерации в record информация из utmp
printf("%-8.8s \n",record.ut_line); //проверю считывается ли при каждой итерации в record информация из utmp
exit(0);
}
else //процесс родитель
{
close(fd[1]); //закрытие межпроцессного канала на запись
read (fd[0], &record2, sizeof(struct utmp));
printf("\nrec2 - %-8.8s ",record2.ut_name);
printf("%-8.8s ",record2.ut_line);
}
}
printf("\n");
close(utmpfd); //закрываем utmp
return 0;
}
===========
результат:
rec1 - reboot ~
rec2 - reboot ~
rec1 - runlevel ~
rec1 - LOGIN tty4
rec2 - reboot ~
rec2 - LOGIN tty4
rec1 - LOGIN tty5
rec2 - P� �p� �
rec1 - LOGIN tty2
rec2 - LOGIN tty4
rec2 - LOGIN tty4
rec1 - LOGIN tty3
rec2 - P� �p� �
rec2 - P� �p� �
rec1 - LOGIN tty6
rec2 - LOGIN tty4
rec2 - LOGIN tty4
rec1 - LOGIN tty1
rec2 - P� �p� �
rec2 - P� �p� �
rec1 - user tty7
rec2 - LOGIN tty4
rec2 - LOGIN tty4
rec1 - user pts/0
rec2 - P� �p� �
rec2 - P� �p� �
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
struct utmp record; // структура для запеси данных из utmp
struct utmp record2;// она же но для записи из межпроцессного канала
int utmpfd; //fd для utmp
int reclen=sizeof(struct utmp); //значение len для read()
int fd[2];
int filefd;
pid_t childpid;
if((utmpfd=open(UTMP_FILE,O_RDONLY))==-1){ //открываем файл utmp
perror(UTMP_FILE);
exit(1);
}
pipe(fd); //создание межпроцессного канала
while(read(utmpfd,&record,reclen)==reclen)
{
if((childpid = fork()) == -1) //проверка на ошибки
{
perror("fork");
exit(1);
}
if(childpid == 0) //процесс потомок
{
close(fd[0]); //закрытие межпроцессного канала на чтение
write (fd[1], &record, sizeof(struct utmp));
printf("\nrec1 - %-8.8s ",record.ut_name); //проверю считывается ли при каждой итерации в record информация из utmp
printf("%-8.8s \n",record.ut_line); //проверю считывается ли при каждой итерации в record информация из utmp
exit(0);
}
else //процесс родитель
{
close(fd[1]); //закрытие межпроцессного канала на запись
read (fd[0], &record2, sizeof(struct utmp));
printf("\nrec2 - %-8.8s ",record2.ut_name);
printf("%-8.8s ",record2.ut_line);
}
}
printf("\n");
close(utmpfd); //закрываем utmp
return 0;
}
===========
результат:
rec1 - reboot ~
rec2 - reboot ~
rec1 - runlevel ~
rec1 - LOGIN tty4
rec2 - reboot ~
rec2 - LOGIN tty4
rec1 - LOGIN tty5
rec2 - P� �p� �
rec1 - LOGIN tty2
rec2 - LOGIN tty4
rec2 - LOGIN tty4
rec1 - LOGIN tty3
rec2 - P� �p� �
rec2 - P� �p� �
rec1 - LOGIN tty6
rec2 - LOGIN tty4
rec2 - LOGIN tty4
rec1 - LOGIN tty1
rec2 - P� �p� �
rec2 - P� �p� �
rec1 - user tty7
rec2 - LOGIN tty4
rec2 - LOGIN tty4
rec1 - user pts/0
rec2 - P� �p� �
rec2 - P� �p� �
Феерично...
вывод данных их процесса потомка ожидаем (rec1), всё правильно, выводит все, что читает в файле utmp, но что-то происходит в процесе передачи по каналу процессу предку...
Уверяю, картина сразу прояснится!
На предмет возвращения значение и установки переменной errno?
Хм...внёс pipe(fd) в тело цикла и всё заработало... ох уж этот Си....
Код:
if (read(...)==-1) {
perror ("read");
....
}
perror ("read");
....
}
write() - аналогично. А вообще - man 2 read.
man 2 write.
Скорее всего дело в том, что при завершении детишки закрываются все его файловые дескрипторы, в том числе и созданные вызовом pipe() и пользоваться ими далее нельзя. Поэтому, родителю нужно закрывать дескриптор, используемый для чтения и создавать новый пайп для каждого нового экземпляра детишки.
Т.е. перетащить pipe() внутрь цикла чтения.
Но нужно закрывать fd[0] в родителе, иначе будут оставаться открытые неиспользуемые дескрипторы, а это количество не бесконечно.
Можно легко посмотреть сколько файлов открыто
Цитата:
ls -l /proc/<pid>/fd
где <pid> - номер процесса.
Ещё один момент, Ваша программа плодит процессы-зомби, по одному на каждую прочитанную запись. Нужно обрабатывать завершение процессов детишек с помощью какой-либо функции wait, waitpid.
А Ваше замечание относительно C я могу прокомментировать только так - ноты надо знать! :) Замена одного языка другим не заставит неправильно написанную программу работать.
Надо-надо, согласен).