Добавил:
Вуз:
Предмет:
Файл:
practic3
.c/*
Выполнил:
Задание №3 Поставщик-потребитель
Дата выполнения 29.03.2026
Версия 0.1
Общее описание программы:
Компиляция: gcc -std=c11 -O2 -Wall -Wextra -pedantic -pthread lab3.c
Запуск:
./a.out sem - семафор
./a.out cond - условная переменная
*/
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
enum {
BUFFER_CAPACITY = 3,
PRODUCER_ITERS = 20,
CONSUMER_ITERS = 20,
PRODUCER_SLEEP_MS = 120,
CONSUMER_SLEEP_MS = 180
};
typedef enum {
MODE_SEMAPHORES = 1,
MODE_CONDVAR = 2
} run_mode_t;
static int Buffer = 0;
static void die_pthread(int rc, const char *what) {
if (rc == 0) return;
errno = rc;
perror(what);
exit(EXIT_FAILURE);
}
static void die_sys(const char *what) {
perror(what);
exit(EXIT_FAILURE);
}
static struct timespec now_ts(void) {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
die_sys("clock_gettime");
}
return ts;
}
static long long ts_to_ns(struct timespec ts) {
return (long long)ts.tv_sec * 1000000000LL + (long long)ts.tv_nsec;
}
static void print_ts(FILE *out, const struct timespec *ts) {
fprintf(out, "%ld.%09ld", (long)ts->tv_sec, ts->tv_nsec);
}
static void ms_sleep(unsigned ms) {
struct timespec req;
req.tv_sec = ms / 1000U;
req.tv_nsec = (long)(ms % 1000U) * 1000000L;
while (nanosleep(&req, &req) == -1) {
if (errno != EINTR) {
die_sys("nanosleep");
}
}
}
static void log_state(const char *who,
const char *phase,
int iteration,
int before,
int after,
struct timespec start,
struct timespec end) {
double dur_ms = (double)(ts_to_ns(end) - ts_to_ns(start)) / 1e6;
printf("[%s] %s #%02d | Buffer: %d -> %d | start=", who, phase, iteration, before, after);
print_ts(stdout, &start);
printf(" | end=");
print_ts(stdout, &end);
printf(" | critical section = %.3f ms\n", dur_ms);
fflush(stdout);
}
//semaphore
static sem_t sem_empty;
static sem_t sem_full;
static sem_t sem_access;
static void *supplier_semaphore(void *arg) {
(void)arg;
for (int i = 1; i <= PRODUCER_ITERS; ++i) {
die_pthread(sem_wait(&sem_empty), "sem_wait(empty)");
die_pthread(sem_wait(&sem_access), "sem_wait(access)");
int before = Buffer;
struct timespec start = now_ts();
Buffer++;
struct timespec end = now_ts();
int after = Buffer;
die_pthread(sem_post(&sem_access), "sem_post(access)");
die_pthread(sem_post(&sem_full), "sem_post(full)");
log_state("SUPPLIER/SEM", "write", i, before, after, start, end);
ms_sleep(PRODUCER_SLEEP_MS);
}
return NULL;
}
static void *consumer_semaphore(void *arg) {
(void)arg;
for (int i = 1; i <= CONSUMER_ITERS; ++i) {
die_pthread(sem_wait(&sem_full), "sem_wait(full)");
die_pthread(sem_wait(&sem_access), "sem_wait(access)");
int before = Buffer;
struct timespec start = now_ts();
Buffer--;
struct timespec end = now_ts();
int after = Buffer;
die_pthread(sem_post(&sem_access), "sem_post(access)");
die_pthread(sem_post(&sem_empty), "sem_post(empty)");
log_state("CONSUMER/SEM", "read", i, before, after, start, end);
ms_sleep(CONSUMER_SLEEP_MS);
}
return NULL;
}
static void run_semaphore_variant(void) {
Buffer = 0;
if (sem_init(&sem_empty, 0, BUFFER_CAPACITY) != 0) die_sys("sem_init(empty)");
if (sem_init(&sem_full, 0, 0) != 0) die_sys("sem_init(full)");
if (sem_init(&sem_access, 0, 1) != 0) die_sys("sem_init(access)");
pthread_t sup, cons;
die_pthread(pthread_create(&cons, NULL, consumer_semaphore, NULL), "pthread_create(consumer)");
die_pthread(pthread_create(&sup, NULL, supplier_semaphore, NULL), "pthread_create(supplier)");
die_pthread(pthread_join(sup, NULL), "pthread_join(supplier)");
die_pthread(pthread_join(cons, NULL), "pthread_join(consumer)");
die_pthread(sem_destroy(&sem_empty), "sem_destroy(empty)");
die_pthread(sem_destroy(&sem_full), "sem_destroy(full)");
die_pthread(sem_destroy(&sem_access), "sem_destroy(access)");
}
//condition variables
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond_not_full = PTHREAD_COND_INITIALIZER;
static pthread_cond_t cond_not_empty = PTHREAD_COND_INITIALIZER;
static void *supplier_condvar(void *arg) {
(void)arg;
for (int i = 1; i <= PRODUCER_ITERS; ++i) {
die_pthread(pthread_mutex_lock(&mtx), "pthread_mutex_lock");
while (Buffer >= BUFFER_CAPACITY) {
die_pthread(pthread_cond_wait(&cond_not_full, &mtx), "pthread_cond_wait(not_full)");
}
int before = Buffer;
struct timespec start = now_ts();
Buffer++;
struct timespec end = now_ts();
int after = Buffer;
die_pthread(pthread_cond_signal(&cond_not_empty), "pthread_cond_signal(not_empty)");
die_pthread(pthread_mutex_unlock(&mtx), "pthread_mutex_unlock");
log_state("SUPPLIER/COND", "write", i, before, after, start, end);
ms_sleep(PRODUCER_SLEEP_MS);
}
return NULL;
}
static void *consumer_condvar(void *arg) {
(void)arg;
for (int i = 1; i <= CONSUMER_ITERS; ++i) {
die_pthread(pthread_mutex_lock(&mtx), "pthread_mutex_lock");
while (Buffer <= 0) {
die_pthread(pthread_cond_wait(&cond_not_empty, &mtx), "pthread_cond_wait(not_empty)");
}
int before = Buffer;
struct timespec start = now_ts();
Buffer--;
struct timespec end = now_ts();
int after = Buffer;
die_pthread(pthread_cond_signal(&cond_not_full), "pthread_cond_signal(not_full)");
die_pthread(pthread_mutex_unlock(&mtx), "pthread_mutex_unlock");
log_state("CONSUMER/COND", "read", i, before, after, start, end);
ms_sleep(CONSUMER_SLEEP_MS);
}
return NULL;
}
static void run_condvar_variant(void) {
Buffer = 0;
pthread_t sup, cons;
die_pthread(pthread_create(&cons, NULL, consumer_condvar, NULL), "pthread_create(consumer)");
die_pthread(pthread_create(&sup, NULL, supplier_condvar, NULL), "pthread_create(supplier)");
die_pthread(pthread_join(sup, NULL), "pthread_join(supplier)");
die_pthread(pthread_join(cons, NULL), "pthread_join(consumer)");
die_pthread(pthread_mutex_destroy(&mtx), "pthread_mutex_destroy");
die_pthread(pthread_cond_destroy(&cond_not_full), "pthread_cond_destroy(not_full)");
die_pthread(pthread_cond_destroy(&cond_not_empty), "pthread_cond_destroy(not_empty)");
}
//main
static mode_t parse_mode(int argc, char **argv) {
if (argc < 2) {
return MODE_SEMAPHORES;
}
if (strcmp(argv[1], "sem") == 0 || strcmp(argv[1], "semaphore") == 0) {
return MODE_SEMAPHORES;
}
if (strcmp(argv[1], "cond") == 0 || strcmp(argv[1], "cv") == 0) {
return MODE_CONDVAR;
}
fprintf(stderr, "Usage: %s [sem|cond]\n", argv[0]);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
mode_t mode = parse_mode(argc, argv);
printf("Producer-Consumer demo | capacity=%d | producer iters=%d | consumer iters=%d\n",
BUFFER_CAPACITY, PRODUCER_ITERS, CONSUMER_ITERS);
printf("Mode: %s\n\n", mode == MODE_SEMAPHORES ? "semaphores" : "condition variables");
if (mode == MODE_SEMAPHORES) {
run_semaphore_variant();
} else {
run_condvar_variant();
}
printf("\nFinished. Final Buffer=%d\n", Buffer);
return EXIT_SUCCESS;
}
/* ЛОГ: start,end - время начала, окончания
@debian:~/Desktop$ gcc -std=c11 -O2 -Wall -Wextra -pedantic -pthread lab3.c
@debian:~/Desktop$ ./a sem
bash: ./a: No such file or directory
@debian:~/Desktop$ ./a.out sem
Producer-Consumer demo | capacity=3 | producer iters=20 | consumer iters=20
Mode: semaphores
[SUPPLIER/SEM] write #01 | Buffer: 0 -> 1 | start=1775220920.885881773 | end=1775220920.885881853 | critical section = 0.000 ms
[CONSUMER/SEM] read #01 | Buffer: 1 -> 0 | start=1775220920.885967024 | end=1775220920.885967064 | critical section = 0.000 ms
[SUPPLIER/SEM] write #02 | Buffer: 0 -> 1 | start=1775220921.006522178 | end=1775220921.006522228 | critical section = 0.000 ms
[CONSUMER/SEM] read #02 | Buffer: 1 -> 0 | start=1775220921.071547528 | end=1775220921.071547579 | critical section = 0.000 ms
[SUPPLIER/SEM] write #03 | Buffer: 0 -> 1 | start=1775220921.127218848 | end=1775220921.127218878 | critical section = 0.000 ms
[SUPPLIER/SEM] write #04 | Buffer: 1 -> 2 | start=1775220921.249885203 | end=1775220921.249885243 | critical section = 0.000 ms
[CONSUMER/SEM] read #03 | Buffer: 2 -> 1 | start=1775220921.257827717 | end=1775220921.257827767 | critical section = 0.000 ms
[SUPPLIER/SEM] write #05 | Buffer: 1 -> 2 | start=1775220921.373021071 | end=1775220921.373021111 | critical section = 0.000 ms
[CONSUMER/SEM] read #04 | Buffer: 2 -> 1 | start=1775220921.439320789 | end=1775220921.439320829 | critical section = 0.000 ms
[SUPPLIER/SEM] write #06 | Buffer: 1 -> 2 | start=1775220921.496829137 | end=1775220921.496829187 | critical section = 0.000 ms
[SUPPLIER/SEM] write #07 | Buffer: 2 -> 3 | start=1775220921.622867166 | end=1775220921.622867206 | critical section = 0.000 ms
[CONSUMER/SEM] read #05 | Buffer: 3 -> 2 | start=1775220921.624942812 | end=1775220921.624942862 | critical section = 0.000 ms
[SUPPLIER/SEM] write #08 | Buffer: 2 -> 3 | start=1775220921.743539445 | end=1775220921.743539495 | critical section = 0.000 ms
[CONSUMER/SEM] read #06 | Buffer: 3 -> 2 | start=1775220921.808588699 | end=1775220921.808588749 | critical section = 0.000 ms
[SUPPLIER/SEM] write #09 | Buffer: 2 -> 3 | start=1775220921.864761859 | end=1775220921.864761909 | critical section = 0.000 ms
[CONSUMER/SEM] read #07 | Buffer: 3 -> 2 | start=1775220921.988936188 | end=1775220921.988936228 | critical section = 0.000 ms
[SUPPLIER/SEM] write #10 | Buffer: 2 -> 3 | start=1775220921.989100950 | end=1775220921.989100990 | critical section = 0.000 ms
[CONSUMER/SEM] read #08 | Buffer: 3 -> 2 | start=1775220922.174985263 | end=1775220922.174985314 | critical section = 0.000 ms
[SUPPLIER/SEM] write #11 | Buffer: 2 -> 3 | start=1775220922.175167834 | end=1775220922.175167894 | critical section = 0.000 ms
[CONSUMER/SEM] read #09 | Buffer: 3 -> 2 | start=1775220922.357256393 | end=1775220922.357256443 | critical section = 0.000 ms
[SUPPLIER/SEM] write #12 | Buffer: 2 -> 3 | start=1775220922.357405847 | end=1775220922.357405887 | critical section = 0.000 ms
[CONSUMER/SEM] read #10 | Buffer: 3 -> 2 | start=1775220922.553873076 | end=1775220922.553873116 | critical section = 0.000 ms
[SUPPLIER/SEM] write #13 | Buffer: 2 -> 3 | start=1775220922.554069565 | end=1775220922.554069615 | critical section = 0.000 ms
[CONSUMER/SEM] read #11 | Buffer: 3 -> 2 | start=1775220922.737433049 | end=1775220922.737433099 | critical section = 0.000 ms
[SUPPLIER/SEM] write #14 | Buffer: 2 -> 3 | start=1775220922.737605014 | end=1775220922.737605074 | critical section = 0.000 ms
[CONSUMER/SEM] read #12 | Buffer: 3 -> 2 | start=1775220922.925777992 | end=1775220922.925778032 | critical section = 0.000 ms
[SUPPLIER/SEM] write #15 | Buffer: 2 -> 3 | start=1775220922.925945193 | end=1775220922.925945233 | critical section = 0.000 ms
[CONSUMER/SEM] read #13 | Buffer: 3 -> 2 | start=1775220923.107431882 | end=1775220923.107431932 | critical section = 0.000 ms
[SUPPLIER/SEM] write #16 | Buffer: 2 -> 3 | start=1775220923.107603278 | end=1775220923.107603338 | critical section = 0.000 ms
[CONSUMER/SEM] read #14 | Buffer: 3 -> 2 | start=1775220923.287713595 | end=1775220923.287713635 | critical section = 0.000 ms
[SUPPLIER/SEM] write #17 | Buffer: 2 -> 3 | start=1775220923.287895767 | end=1775220923.287895816 | critical section = 0.000 ms
[CONSUMER/SEM] read #15 | Buffer: 3 -> 2 | start=1775220923.467911259 | end=1775220923.467911299 | critical section = 0.000 ms
[SUPPLIER/SEM] write #18 | Buffer: 2 -> 3 | start=1775220923.468081265 | end=1775220923.468081305 | critical section = 0.000 ms
[CONSUMER/SEM] read #16 | Buffer: 3 -> 2 | start=1775220923.655027017 | end=1775220923.655027067 | critical section = 0.000 ms
[SUPPLIER/SEM] write #19 | Buffer: 2 -> 3 | start=1775220923.655187677 | end=1775220923.655187727 | critical section = 0.000 ms
[CONSUMER/SEM] read #17 | Buffer: 3 -> 2 | start=1775220923.837445961 | end=1775220923.837446010 | critical section = 0.000 ms
[SUPPLIER/SEM] write #20 | Buffer: 2 -> 3 | start=1775220923.837623179 | end=1775220923.837623219 | critical section = 0.000 ms
[CONSUMER/SEM] read #18 | Buffer: 3 -> 2 | start=1775220924.022171573 | end=1775220924.022171623 | critical section = 0.000 ms
[CONSUMER/SEM] read #19 | Buffer: 2 -> 1 | start=1775220924.202857802 | end=1775220924.202857832 | critical section = 0.000 ms
[CONSUMER/SEM] read #20 | Buffer: 1 -> 0 | start=1775220924.385623008 | end=1775220924.385623058 | critical section = 0.000 ms
Finished. Final Buffer=0
@debian:~/Desktop$ ./a.out cond
Producer-Consumer demo | capacity=3 | producer iters=20 | consumer iters=20
Mode: condition variables
[SUPPLIER/COND] write #01 | Buffer: 0 -> 1 | start=1775220933.747235899 | end=1775220933.747235979 | critical section = 0.000 ms
[CONSUMER/COND] read #01 | Buffer: 1 -> 0 | start=1775220933.747306798 | end=1775220933.747306838 | critical section = 0.000 ms
[SUPPLIER/COND] write #02 | Buffer: 0 -> 1 | start=1775220933.872805180 | end=1775220933.872805230 | critical section = 0.000 ms
[CONSUMER/COND] read #02 | Buffer: 1 -> 0 | start=1775220933.929331956 | end=1775220933.929331996 | critical section = 0.000 ms
[SUPPLIER/COND] write #03 | Buffer: 0 -> 1 | start=1775220933.994146691 | end=1775220933.994146721 | critical section = 0.000 ms
[SUPPLIER/COND] write #04 | Buffer: 1 -> 2 | start=1775220934.114519631 | end=1775220934.114519681 | critical section = 0.000 ms
[CONSUMER/COND] read #03 | Buffer: 2 -> 1 | start=1775220934.114810507 | end=1775220934.114810547 | critical section = 0.000 ms
[SUPPLIER/COND] write #05 | Buffer: 1 -> 2 | start=1775220934.238505646 | end=1775220934.238505696 | critical section = 0.000 ms
[CONSUMER/COND] read #04 | Buffer: 2 -> 1 | start=1775220934.296703347 | end=1775220934.296703397 | critical section = 0.000 ms
[SUPPLIER/COND] write #06 | Buffer: 1 -> 2 | start=1775220934.359147958 | end=1775220934.359147998 | critical section = 0.000 ms
[CONSUMER/COND] read #05 | Buffer: 2 -> 1 | start=1775220934.476914586 | end=1775220934.476914636 | critical section = 0.000 ms
[SUPPLIER/COND] write #07 | Buffer: 1 -> 2 | start=1775220934.487002133 | end=1775220934.487002163 | critical section = 0.000 ms
[SUPPLIER/COND] write #08 | Buffer: 2 -> 3 | start=1775220934.612227567 | end=1775220934.612227617 | critical section = 0.000 ms
[CONSUMER/COND] read #06 | Buffer: 3 -> 2 | start=1775220934.660427176 | end=1775220934.660427226 | critical section = 0.000 ms
[SUPPLIER/COND] write #09 | Buffer: 2 -> 3 | start=1775220934.736506659 | end=1775220934.736506699 | critical section = 0.000 ms
[CONSUMER/COND] read #07 | Buffer: 3 -> 2 | start=1775220934.842455375 | end=1775220934.842455425 | critical section = 0.000 ms
[SUPPLIER/COND] write #10 | Buffer: 2 -> 3 | start=1775220934.861089659 | end=1775220934.861089699 | critical section = 0.000 ms
[CONSUMER/COND] read #08 | Buffer: 3 -> 2 | start=1775220935.022786035 | end=1775220935.022786085 | critical section = 0.000 ms
[SUPPLIER/COND] write #11 | Buffer: 2 -> 3 | start=1775220935.022859961 | end=1775220935.022860001 | critical section = 0.000 ms
[CONSUMER/COND] read #09 | Buffer: 3 -> 2 | start=1775220935.210725495 | end=1775220935.210725546 | critical section = 0.000 ms
[SUPPLIER/COND] write #12 | Buffer: 2 -> 3 | start=1775220935.210848938 | end=1775220935.210848988 | critical section = 0.000 ms
[CONSUMER/COND] read #10 | Buffer: 3 -> 2 | start=1775220935.396806508 | end=1775220935.396806559 | critical section = 0.000 ms
[SUPPLIER/COND] write #13 | Buffer: 2 -> 3 | start=1775220935.396958063 | end=1775220935.396958123 | critical section = 0.000 ms
[CONSUMER/COND] read #11 | Buffer: 3 -> 2 | start=1775220935.582316523 | end=1775220935.582316572 | critical section = 0.000 ms
[SUPPLIER/COND] write #14 | Buffer: 2 -> 3 | start=1775220935.582508511 | end=1775220935.582508560 | critical section = 0.000 ms
[CONSUMER/COND] read #12 | Buffer: 3 -> 2 | start=1775220935.764253678 | end=1775220935.764253718 | critical section = 0.000 ms
[SUPPLIER/COND] write #15 | Buffer: 2 -> 3 | start=1775220935.764429264 | end=1775220935.764429304 | critical section = 0.000 ms
[CONSUMER/COND] read #13 | Buffer: 3 -> 2 | start=1775220935.950802952 | end=1775220935.950803002 | critical section = 0.000 ms
[SUPPLIER/COND] write #16 | Buffer: 2 -> 3 | start=1775220935.950929944 | end=1775220935.950929974 | critical section = 0.000 ms
[CONSUMER/COND] read #14 | Buffer: 3 -> 2 | start=1775220936.132634110 | end=1775220936.132634160 | critical section = 0.000 ms
[SUPPLIER/COND] write #17 | Buffer: 2 -> 3 | start=1775220936.132779015 | end=1775220936.132779064 | critical section = 0.000 ms
[CONSUMER/COND] read #15 | Buffer: 3 -> 2 | start=1775220936.316411564 | end=1775220936.316411604 | critical section = 0.000 ms
[SUPPLIER/COND] write #18 | Buffer: 2 -> 3 | start=1775220936.316558095 | end=1775220936.316558145 | critical section = 0.000 ms
[CONSUMER/COND] read #16 | Buffer: 3 -> 2 | start=1775220936.498145533 | end=1775220936.498145583 | critical section = 0.000 ms
[SUPPLIER/COND] write #19 | Buffer: 2 -> 3 | start=1775220936.498303113 | end=1775220936.498303164 | critical section = 0.000 ms
[CONSUMER/COND] read #17 | Buffer: 3 -> 2 | start=1775220936.684233829 | end=1775220936.684233879 | critical section = 0.000 ms
[SUPPLIER/COND] write #20 | Buffer: 2 -> 3 | start=1775220936.684381320 | end=1775220936.684381360 | critical section = 0.000 ms
[CONSUMER/COND] read #18 | Buffer: 3 -> 2 | start=1775220936.868898955 | end=1775220936.868899006 | critical section = 0.000 ms
[CONSUMER/COND] read #19 | Buffer: 2 -> 1 | start=1775220937.063082330 | end=1775220937.063082370 | critical section = 0.000 ms
[CONSUMER/COND] read #20 | Buffer: 1 -> 0 | start=1775220937.243375815 | end=1775220937.243375855 | critical section = 0.000 ms
Finished. Final Buffer=0
@debian:~/Desktop$
*/
Соседние файлы в предмете Системы реального времени
