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

Ваш аккаунт

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

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

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

Не получается передать данные по межпроцессному каналу

49K
22 ноября 2009 года
abskura
11 / / 22.11.2009
И так.

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


Объявляю переменные, открываю файл utmp с информацией о пользователях и создаю межпроцессный канал:
Код:
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); //создание межпроцессного канала


Далее непосредственно процесс передачи в параллельный процесс:

Код:
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);
        }
       
}


Проблема в том, что результат печати выглядит следующим образом:
 
Код:
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


Код целиком:
Код:
#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&#65533;    &#65533;p&#65533;    &#65533;          
rec1 - LOGIN    tty2    
rec2 - LOGIN    tty4    
rec2 - LOGIN    tty4    
rec1 - LOGIN    tty3    
rec2 - P&#65533;    &#65533;p&#65533;    &#65533;          
rec2 - P&#65533;    &#65533;p&#65533;    &#65533;          
rec1 - LOGIN    tty6    
rec2 - LOGIN    tty4    
rec2 - LOGIN    tty4    
rec1 - LOGIN    tty1    
rec2 - P&#65533;    &#65533;p&#65533;    &#65533;          
rec2 - P&#65533;    &#65533;p&#65533;    &#65533;          
rec1 - user     tty7    
rec2 - LOGIN    tty4    
rec2 - LOGIN    tty4    
rec1 - user     pts/0    
rec2 - P&#65533;    &#65533;p&#65533;    &#65533;          
rec2 - P&#65533;    &#65533;p&#65533;    &#65533;


Феерично...
вывод данных их процесса потомка ожидаем (rec1), всё правильно, выводит все, что читает в файле utmp, но что-то происходит в процесе передачи по каналу процессу предку...
43K
22 ноября 2009 года
loki231
76 / / 27.09.2009
Для того, чтобы разобраться в происходящем, рекомендуется проверить результаты выполнения системных вызовов read() и write() (И делать так всегда).

Уверяю, картина сразу прояснится!
49K
22 ноября 2009 года
abskura
11 / / 22.11.2009
А проверять каким способом?
На предмет возвращения значение и установки переменной errno?
49K
22 ноября 2009 года
abskura
11 / / 22.11.2009
Хм...внёс pipe(fd) в тело цикла и всё заработало... ох уж этот Си....
43K
22 ноября 2009 года
loki231
76 / / 27.09.2009
Проверять так:

 
Код:
if (read(...)==-1) {
     perror ("read");
     ....
}


write() - аналогично. А вообще - man 2 read.
man 2 write.

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

Т.е. перетащить pipe() внутрь цикла чтения.

Но нужно закрывать fd[0] в родителе, иначе будут оставаться открытые неиспользуемые дескрипторы, а это количество не бесконечно.

Можно легко посмотреть сколько файлов открыто

Цитата:

ls -l /proc/<pid>/fd



где <pid> - номер процесса.

Ещё один момент, Ваша программа плодит процессы-зомби, по одному на каждую прочитанную запись. Нужно обрабатывать завершение процессов детишек с помощью какой-либо функции wait, waitpid.

А Ваше замечание относительно C я могу прокомментировать только так - ноты надо знать! :) Замена одного языка другим не заставит неправильно написанную программу работать.

49K
22 ноября 2009 года
abskura
11 / / 22.11.2009
Спасибо, про зомби-то я забыл совсем).
Надо-надо, согласен).

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог