Files
CS-LABS/vlad/lab_5/worker.c
2025-12-10 16:47:58 +07:00

124 lines
4.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define _GNU_SOURCE // для определения расширенных возможностей glibc
#include <errno.h>
#include <mqueue.h> // POSIX очереди сообщений: mq_open, mq_send, mq_receive
#include <signal.h>
#include <stdint.h>
#include <stdio.h> // fprintf, perror, dprintf
#include <stdlib.h> // atoi, rand_r
#include <string.h> // memset, strncpy, snprintf
#include <sys/stat.h> // права для mq_open (0666)
#include <time.h> // time(), nanosleep, struct timespec
#include <unistd.h> // getpid, STDOUT_FILENO
#include "common.h" // REQ_QUEUE, NAME_MAXLEN, req_msg_t, rep_msg_t
// Пауза на заданное количество миллисекунд
static void msleep(int ms) {
struct timespec ts = {
.tv_sec = ms / 1000,
.tv_nsec = (ms % 1000) * 1000000L
};
nanosleep(&ts, NULL);
}
int main(int argc, char **argv) {
// Ожидается один аргумент: сколько мёда пчела просит за раз
if (argc != 2) {
fprintf(stderr, "Usage: %s <bee_portion>\n", argv[0]);
return 2;
}
int portion = atoi(argv[1]);
if (portion <= 0) {
fprintf(stderr, "portion must be >0\n");
return 2;
}
// PID пчелы и имя её личной очереди ответов
pid_t me = getpid();
char replyq[NAME_MAXLEN];
snprintf(replyq, sizeof(replyq), "/bee_%d", (int) me);
// На всякий случай удаляем старую очередь с таким именем
mq_unlink(replyq);
// Атрибуты очереди ответов (куда сервер будет слать rep_msg_t)
struct mq_attr attr;
memset(&attr, 0, sizeof(attr));
attr.mq_maxmsg = 10;
attr.mq_msgsize = sizeof(rep_msg_t);
// Создаём очередь ответов пчелы, только для чтения
mqd_t qrep = mq_open(replyq, O_CREAT | O_RDONLY, 0666, &attr);
if (qrep == (mqd_t) -1) {
perror("mq_open reply");
return 1;
}
// Открываем очередь запросов к серверу (общая очередь REQ_QUEUE)
mqd_t qreq = -1;
for (int i = 0; i < 50; i++) {
qreq = mq_open(REQ_QUEUE, O_WRONLY);
if (qreq != -1) break; // удалось открыть — выходим из цикла
if (errno != ENOENT) {
// другая ошибка, не "очередь ещё не создана"
perror("mq_open req");
break;
}
// Если сервер ещё не создал очередь (ENOENT) — подождать и попробовать снова
msleep(100);
}
if (qreq == -1) {
// Не смогли открыть очередь запросов — выходим
perror("mq_open req");
mq_close(qrep);
mq_unlink(replyq);
return 1;
}
// Инициализация отдельного генератора случайных чисел для этой пчелы
unsigned seed = (unsigned) (time(NULL) ^ (uintptr_t) me);
// Основной рабочий цикл пчелы
while (1) {
// Ждём случайное время 100699 мс перед очередным запросом
int ms = 100 + (rand_r(&seed) % 600);
msleep(ms);
// Формируем запрос к серверу
req_msg_t req;
memset(&req, 0, sizeof(req));
req.pid = me;
req.want = portion; // сколько мёда хотим получить
strncpy(req.replyq, replyq, sizeof(req.replyq) - 1); // куда слать ответ
// Отправляем запрос в очередь REQ_QUEUE
if (mq_send(qreq, (const char *) &req, sizeof(req), 0) == -1) {
perror("mq_send");
break;
}
// Ждём ответ от сервера в своей очереди
rep_msg_t rep;
ssize_t rd = mq_receive(qrep, (char *) &rep, sizeof(rep), NULL);
if (rd == -1) {
perror("mq_receive");
break;
}
// Если нам больше ничего не дают (granted <= 0) — выходим
if (rep.granted <= 0) {
break;
}
// Иначе логируем, сколько мёда получили и сколько осталось у сервера
dprintf(STDOUT_FILENO, "Bee %d got %d, remain %d\n",
(int) me, rep.granted, rep.remain);
}
// Очистка ресурсов: закрываем очереди и удаляем личную очередь ответов
mq_close(qreq);
mq_close(qrep);
mq_unlink(replyq);
return 0;
}