Страницы

Поиск по вопросам

вторник, 7 мая 2019 г.

Совместное использование сигналов и каналов

Никак не могу разобраться как решить задачу на совместное использование сигналов и каналов (пинг-понг) . Вот условие:
Написать программу игры в "пинг-понг" двух процессов через один канал. Первый процесс посылает второму 1, второй первому – 2, первый второму – 3, второй первому – 4 и т.д. Для синхронизации использовать сигнал. Игра завершается при нажатии клавиш Ctrl+C.
Вот мой код:
#include #include #include #include #include
int cnt=0;
int main(){ int fd[2]; pipe(fd); if(fork()==0){ write(fd[1],&cnt,sizeof(int)); while(read(fd[0],&cnt,sizeof(int))){//Дочерний процесс начинает пинг-понг printf("%d
",cnt); cnt++; write(fd[1],&cnt,sizeof(int)); } close(fd[1]); close(fd[0]); exit(1); } while(read(fd[0],&cnt,sizeof(int))){ printf("%d
",cnt); write(fd[1],&cnt,sizeof(int)); } close(fd[1]); close(fd[0]); return 0; }


Ответ

Поскольку процессы должны общаться через один канал, а канал имеет некоторый буфер, позволяющий писать несколько байт без читающего, процесс вызывающий read после write может прочитать собственные данные, в чём легко убедиться запустив немного исправленную вашу программу:
#include #include #include #include #include
int cnt=0;
int main(){ int fd[2]; pipe(fd); if(fork()==0){ printf("2 w%d
",cnt); write(fd[1],&cnt,sizeof(int)); while(cnt<100 && read(fd[0],&cnt,sizeof(int))){//Дочерний процесс начинает пинг-понг printf("2 r%d
",cnt); cnt++; printf("2 w%d
",cnt); write(fd[1],&cnt,sizeof(int)); } close(fd[1]); close(fd[0]); exit(1); } while(cnt<100 && read(fd[0],&cnt,sizeof(int))){ printf("1 r%d
",cnt); cnt++; printf("1 w%d
",cnt); write(fd[1],&cnt,sizeof(int)); } close(fd[1]); close(fd[0]); return 0; }
Результаты:
$ ./a.out 2 w0 1 r0 1 w1 1 r1 1 w2 1 r2 1 w3 1 r3 1 w4 1 r4 1 w5 1 r5 1 w6 1 r6 1 w7 1 r7 1 w8 1 r8 1 w9 1 r9 1 w10
Первый процесс сам справляется, а второй ему изредка помогает. Необходимо чтобы каждый процесс после записи очередного числа ожидал готовности данных для него, блокирующее чтение тут не поможет, так как данные в канале уже есть.
Для ожидания можно бы использовать функцию pause(), но если сигнал придёт до входа в неё, это приведёт к бесконечному ожиданию, поэтому лучше sleep(1) в цикле с проверкой флага, который изменяется в функции-перехватчике сигнала.
Программа с обменом сигналами.
#include #include #include #include #include
int cnt=0; int signaled=0;
void intr(int n) { // обработчик сигнала signaled=1; }
int main(){ int fd[2]; pipe(fd); int pid; signal(SIGUSR1, intr); if((pid=fork())==0){ // Дочерний процесс начинает пинг-понг pid= getppid(); printf("%d w%d
",pid,cnt); kill(pid, SIGUSR1); write(fd[1],&cnt,sizeof(int)); } while(1) { while(!signaled) sleep(1); if(read(fd[0],&cnt,sizeof(int))<=0) break; printf("%d r%d
",pid,cnt); cnt++; printf("%d w%d
",pid,cnt); signaled=0; // после kill в любом месте может прийти ответ, поэтому здесь обнуляем флаг signal(SIGUSR1, intr); kill(pid, SIGUSR1); write(fd[1],&cnt,sizeof(int)); } close(fd[1]); close(fd[0]); return 0; }
Примечание. Иногда процессы приостанавливаются на одну секунду, это значит сигнал пришёл после проверки условия, но перед ожиданием сигнала внутри sleep()

Комментариев нет:

Отправить комментарий