-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathsection3_5.tex
More file actions
87 lines (85 loc) · 8.7 KB
/
section3_5.tex
File metadata and controls
87 lines (85 loc) · 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{ %section3_5
\subsection{POSIX Threads}
\label{PThreads:section}
\par\textbf{Потоки POSIX.}
\par В данной библиотеке более 100 разных функций, но всех их можно разделить на 4 основные группы:
\begin{itemize}
\itemУправление потоками: create, join и т.д.
\itemМьютексы.
\itemУсловные переменные.
\itemСинхронизация между тредами.
\end{itemize}
\parДля того чтобы воспользоваться библиотекой PThreads в Unix-like и POSIX-совместимой опреационной системе достаточно подключить следующий заголовочный файл PThreads:
\begin{figure}[H]
\lstinputlisting{IncludePThreads.c}
\end{figure}
\parВ отличии от OpenMP, PThreads является более низкоуровневой библиотекой, где от разработчика требуется заранее продумать всю логику работы потоков.
\parРассмотрим задачу добавление числа 10 к каждому элементу массива:
\begin{figure}[H]
\lstinputlisting{WithoutPosix.c}
\end{figure}
\parТеперь воспользуемся библиотекой PThreads для распараллеливания данной задачи(Для понимания того, что происходит приведен код всей программы):
\begin{figure}[H]
\lstinputlisting{WithPosix.c}
\end{figure}
\parТеперь разберем, что происходит в данной программе. Начнем с инициализации тредов:
\begin{figure}[H]
\lstinputlisting{InitPosix.c}
\end{figure}
\parВ данном коде представлено два варианта того, как можно инициализировать несколько потоков. Это может быть, как отдельная переменная, так и массив потоков.
\parПосле инициализации необходимо создать поток:
\begin{figure}[H]
\lstinputlisting{CreatePosix.c}
\end{figure}
\parФункция pthread\_create принимает 4 параметра: указатель на поток, атрибуты потока(если используются атрибуты по умолчанию, то передается NULL), функция которую будет выполнять поток, аргумент функции.
\parВ случае, если поток успешно создан, возвращается 0. Иначе, могут быть вовзращены следующие значения:
\begin{itemize}
\item EAGAIN – у системы нет ресурсов для создания нового потока, или система не может больше создавать потоков, так как количество потоков превысило значение PTHREAD\_THREADS\_MAX.
\item EINVAL – неправильные атрибуты потока (переданные аргументом attr).
\item EPERM – Вызывающий поток не имеет должных прав для того, чтобы задать нужные параметры или политики планировщика.
\end{itemize}
\parВсе коды ошибок можно изучить по данной ссылке \url{https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html}.
\parАргумент функции должен быть типа *void. Чтобы передать несколько параметров, их необходимо обернуть в структуру. В нашем случае необходимо передать указатель на массив и интервал на котором необходимо провести вычисления:
\begin{figure}[H]
\lstinputlisting{ThreadStruct.c}
\end{figure}
\parСразу после создания потока, он начинает выполнение. По стандарту выход из функции вызывает функцию pthread\_exit, а возвращаемое значение будет передано при вызове pthread\_join, как статус.
\parВ свою очередь функция pthread\_join заставляет, основной поток ожидать завершения порожденных им потоков.
\parПри успешном завершении потока, функция pthread\_join возвращает 0, иначе данная функция может вывести следующие ошибки:
\begin{itemize}
\item EINVAL – thread указывает на не объединяемый поток.
\item ESRCH – не существует потока с таким идентификатором, который хранит переменная thread.
\item EDEADLK – был обнаружен дедлок (взаимная блокировка), или же в качестве объединяемого потока указан сам вызывающий поток.
\end{itemize}
\par\textbf{Механизмы синхронизации потоков.} Взаимное исключение\textit{mutex} выполняет функцию ограничения доступа потоков к одному ресурсу. Mutex - переменная, которая может быть или заблокирована, или свободна. При этом, если один поток её заблокировал, другие потоки будут ожидать освобождения ресурса.
\begin{figure}[H]
\lstinputlisting{MutexExample.c}
\end{figure}
\par pthread\_mutex\_t тип данных описывающий mutex. Атрибуты mutex можно контролировать функцией
pthread\_mutex\_init().
\parРассмотрим пример функции в которой необходима синхронизация:
\begin{figure}[H]
\lstinputlisting{WithoutMutex.c}
\end{figure}
\parДанная программа добавляет значения элементов массива в глобальную переменную sum, при обращении нескольких потоков к данной переменной, конечный результат может измениться.
\parНеобходимо добавить mutex в данную функцию, который бы ограничил доступ к данной переменной одновременно нескольким потокам. Тогда программа будет выглядеть следующим образом:
\begin{figure}[H]
\lstinputlisting{WithMutex.c}
\end{figure}
\par\textbf{Семафор.}Следующим примитивом синхронизации является семафор. Его задача такая же, как и у mutex, главное отличие в том, что mutex захватывает один поток в то время, как семафор может захватывать несколько потоков.
\parЧтобы воспользоваться семафором, необходимо подключить заголовочный файл:
\begin{figure}[H]
\lstinputlisting{IncludeSemaphore.c}
\end{figure}
\parВажно, что семафор после окончания работы с ним, необходимо удалять, как это показано ниже:
\begin{figure}[H]
\lstinputlisting{SemaphoreInit.c}
\end{figure}
\parФункция sem\_init() принимает следующие параметры: *sem - объект который необходимо инициализировать, pshared - (0) данный семафор будет общим для всех потоков, (1) общим для процессов, value - начальное значение семафора.
\par\sloppyПодробнее об остальных особенностях POSIX Threads можно прочитать на следующих ресурсах:
\begin{enumerate}
\sloppy
\item Статья habr: \url{https://habr.com/ru/post/326138/}
\item Сайт со всей необходимой документацией: \url{https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html}
\end{enumerate}
}