pr5_sysprog/guess_signals.c
2025-04-06 18:42:54 +03:00

147 lines
5.3 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/wait.h>
volatile sig_atomic_t start_signal_received = 0;
void sig_start_handler(int sig, siginfo_t *info, void *ucontext) {
start_signal_received = 1;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
fprintf(stderr, "Использование: %s N\n", argv[0]);
exit(EXIT_FAILURE);
}
int N = atoi(argv[1]);
if(N <= 0) {
fprintf(stderr, "N должно быть положительным числом\n");
exit(EXIT_FAILURE);
}
srand(time(NULL) ^ getpid());
int total_rounds = 10; // минимум 10 раундов
// Создаем второй процесс
pid_t child_pid = fork();
if(child_pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
sigset_t mask, oldmask;
sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN);
sigaddset(&mask, SIGRTMIN+1);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sig_start_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGRTMIN+1, &sa, NULL);
int round;
for(round = 1; round <= total_rounds; round++) {
int is_parent = (child_pid > 0);
int secret_holder;
if(is_parent) {
secret_holder = (round % 2 == 1);
} else {
secret_holder = (round % 2 == 0);
}
if(secret_holder) {
int secret = (rand() % N) + 1;
printf("Раунд %d: Процесс %d (ЗАГАДЫВАЮЩИЙ) загадывает число.\n", round, getpid());
fflush(stdout);
struct timeval start, end;
gettimeofday(&start, NULL);
int attempts = 0;
int guessed = 0;
pid_t other_pid = (is_parent ? child_pid : getppid());
kill(other_pid, SIGRTMIN+1);
while(!guessed) {
siginfo_t si;
int sig = sigwaitinfo(&mask, &si);
if(sig == SIGRTMIN) {
int guess = si.si_value.sival_int;
attempts++;
printf("Раунд %d: Процесс %d (ЗАГАДЫВАЮЩИЙ) получил догадку: %d\n", round, getpid(), guess);
fflush(stdout);
if(guess == secret) {
kill(other_pid, SIGUSR1);
guessed = 1;
} else {
kill(other_pid, SIGUSR2);
}
}
}
gettimeofday(&end, NULL);
double elapsed = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)/1000000.0;
printf("Раунд %d: Процесс %d (ЗАГАДЫВАЮЩИЙ) завершил раунд. Попыток: %d, время: %.3f сек.\n",
round, getpid(), attempts, elapsed);
fflush(stdout);
} else {
while(!start_signal_received) {
sigsuspend(&oldmask);
}
start_signal_received = 0; // сбрасываем флаг
printf("Раунд %d: Процесс %d (УГАДЫВАЮЩИЙ) начинает угадывать.\n", round, getpid());
fflush(stdout);
struct timeval start, end;
gettimeofday(&start, NULL);
int attempts = 0;
int guess = 0;
int guessed = 0;
while(!guessed) {
guess++; // последовательный перебор от 1
attempts++;
union sigval value;
value.sival_int = guess;
pid_t other_pid;
if(is_parent) {
other_pid = child_pid;
} else {
other_pid = getppid();
}
sigqueue(other_pid, SIGRTMIN, value);
printf("Раунд %d: Процесс %d (УГАДЫВАЮЩИЙ) отправил догадку: %d\n", round, getpid(), guess);
fflush(stdout);
// Ожидаем ответа: SIGUSR1 (верно) или SIGUSR2 (неверно)
siginfo_t si;
int sig = sigwaitinfo(&mask, &si);
if(sig == SIGUSR1) {
guessed = 1;
printf("Раунд %d: Процесс %d (УГАДЫВАЮЩИЙ) получил верный ответ для догадки %d.\n", round, getpid(), guess);
fflush(stdout);
} else if(sig == SIGUSR2) {
// Продолжаем угадывать
}
}
gettimeofday(&end, NULL);
double elapsed = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)/1000000.0;
printf("Раунд %d: Процесс %d (УГАДЫВАЮЩИЙ) завершил раунд. Попыток: %d, время: %.3f сек.\n",
round, getpid(), attempts, elapsed);
fflush(stdout);
}
}
// По окончании раундов родитель ожидает завершения дочернего процесса
if(child_pid > 0) {
wait(NULL);
}
return 0;
}