Никак не могу разобраться как решить задачу на совместное использование сигналов и каналов (пинг-понг) .
Вот условие:
Написать программу игры в "пинг-понг" двух процессов через один канал.
Первый процесс посылает второму 1, второй первому – 2, первый второму
– 3, второй первому – 4 и т.д. Для синхронизации использовать сигнал.
Игра завершается при нажатии клавиш Ctrl+C.
Вот мой код:
#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
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
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()
Комментариев нет:
Отправить комментарий