mirror of https://github.com/t1meshift/os_labs.git
34 lines
2.6 KiB
Markdown
34 lines
2.6 KiB
Markdown
|
# Лабораторная работа №13
|
|||
|
|
|||
|
Для тестирования трёх вариантов реализации очереди были реализованы следующие тесты:
|
|||
|
|
|||
|
1. `empty_queue_test()` для теста проблемы producer-consumer. Если программа некорректно
|
|||
|
работает при наличии потоков-потребителей, она выдаст ошибку при попытке взять элемент из
|
|||
|
пустой очереди.
|
|||
|
|
|||
|
2. `thread_safe_test()` для проверки корректности работы многопоточности. Идея заключается
|
|||
|
в заполнении очереди ненулевыми значениями из нескольких потоков. Если программа работает некорректно на нескольких
|
|||
|
потоках, то программа выдаст ошибку. Ошибка определяется в наличии нулей между ненулевыми значениями,
|
|||
|
которые могут оказаться там ввиду гонок данных, например, в `queue_push()`.
|
|||
|
|
|||
|
Тесты лежат в отдельном файле [testing.ic](./testing.ic), этот файл инклудится в каждой из программ.
|
|||
|
|
|||
|
Результаты предсказуемы:
|
|||
|
|
|||
|
- наивная реализация не проходит мультипоточный тест (producer-consumer,
|
|||
|
очевидно, тоже);
|
|||
|
- реализация на мьютексах корректно работает с несколькими потоками, но проблема producer-consumer
|
|||
|
остаётся;
|
|||
|
- реализация с использованием условных переменных проходит все тесты.
|
|||
|
|
|||
|
В наивной реализации проблемы начинаются в `queue_push()`.
|
|||
|
В этом участке кода происходит data race, а так как `next_in` ничем не защищён, следовательно,
|
|||
|
двойной инкремент неизбежен при достаточно большом размере очереди.
|
|||
|
```c
|
|||
|
queue->array[queue->next_in] = item;
|
|||
|
queue->next_in = queue_incr(queue, queue->next_in);
|
|||
|
```
|
|||
|
|
|||
|
Для решения проблемы producer-consumer была добавлена conditional variable для
|
|||
|
проверки на пустоту очереди, тем самым поток-потребитель дождётся, пока в очереди
|
|||
|
не появится хотя бы один элемент.
|