Материал: ОСиС. Лабораторная работа 5

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Алгоритм решения аналогичен алгоритму решения на основе монитора1. (Недостатком является отсутствие решения проблемы голодания: один из философов (или несколько) может долго ждать своих соседей.)

Запустим программу на выполнение и проверим её работу (рис. 5).

Рисунок 5 — Работа алгоритма решения задачи об обедающих философах В данном случае мы использовали C++, а не Си, так как задача лежит

ближе к ООП, нежели к чисто процедурной парадигме. В соответствии с выбранной парадигмой и языком, мы выбрали класс thread библиотеки поддержки потоков языка C++. Методы и их описания приведены в табл. 3.

Таблица 3 — Методы класса thread (#include <thread>)

bool joinable() const noexcept;

Проверяет, можно ли вызвать метод join;

 

 

std::thread::id get_id() const

Возвращает идентификатор потока;

noexcept;

native_handle_type

Возвращает базовый дескриптор потока,

native_handle();

определяемый реализацией;

1https://ru.wikipedia.org/wiki/Задача_об_обедающих_философах#Решение_на_основе_монитора

6

static unsigned int

Возвращает количество параллельных

hardware_concurrency()

потоков, поддерживаемых реализацией;

noexcept;

 

 

void join();

Ждет, пока поток закончит свое

выполнение;

 

 

Отделяет поток от объекта thread, позволяя

void detach();

потоку продолжить выполнение

 

независимо;

void swap(std::thread& other)

Меняет местами два объекта потока.

noexcept;

По желанию можно переписать эту программу с использованием

POSIX функций (табл. 4).

 

Таблица 4 — Функции POSIX для работы с потоками (#include <pthread.h>)

int pthread_create(pthread_t

Создает поток, идентификатор созданного

*restrict thread, const

pthread_attr_t *restrict attr,

потока возвращается в качестве выходного

void *(*start_routine)(void*),

параметра;

void *restrict arg);

 

pthread_t pthread_self(void);

Получает идентификатор текущего потока;

Сравнивает два идентификатора потоков

(может использоваться, к примеру, для int pthread_equal(pthread_t t1, сравнения некоторого идентификатора

pthread_t t2);

потока со значением, возвращаемым

функцией pthread_self);

int pthread_join(pthread_t

Ожидает завершения некоторого потока и

освобождает ресурсы, выделенные при его

thread, void **status);

 

создании;

int pthread_detach(pthread_t

Отделяет поток от дескриптора thread,

позволяя потоку продолжить выполнение

thread);

 

независимо;

void pthread_exit(void

Завершает текущий поток;

*value_ptr);

int pthread_cancel(pthread_t

Запрашивает принудительное завершение

target_thread);

другого потока.

Важно не путать POSIX функции и функции языка Си (табл. 5) для работы с потоками.

Таблица 5 — Функции языка C для работы с потоками (#include <threads.h>)

int thrd_create(thrd_t *thr,

Создает поток;

thrd_start_t func, void *arg);

int thrd_equal(thrd_t lhs,

Проверяет, относятся ли два

thrd_t rhs);

идентификатора к одному и тому же потоку;

thrd_t thrd_current(void);

Получает идентификатор текущего потока;

 

 

int thrd_sleep(const struct

Приостанавливает выполнение

timespec* duration, struct

 

7

timespec* remaining);

 

вызывающего потока на заданный период

 

времени;

 

 

 

 

 

 

void thrd_yield(void);

 

Дает подсказку реализации об ожидании;

 

 

 

 

_Noreturn void thrd_exit(int

 

Завершает вызывающий поток;

res);

 

int thrd_detach(thrd_t thr);

 

Отделяет поток от дескриптора thr;

 

 

 

 

int thrd_join(thrd_t thr, int

 

Блокируется, пока поток не завершится.

*res);

 

Заключение В результате выполнения лабораторной работы мы ознакомились с

применением механизмов синхронизации потоков под Linux.

8