Файл: Методические указания по выполнению самостоятельной работы обучающихся практических занятий.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 22.11.2023

Просмотров: 15

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Омская гуманитарная академия









МЕТОДИЧЕСКИЕ УКАЗАНИЯ

по выполнению самостоятельной работы обучающихся


практических занятий

Инфокоммуникационные технологии

Саодат Тургабаевна Арзекеева

Омск, 2022

Команды управления потоками MS Windows

Процесс (process) – это отдельная исполняемая программа с используемой ею памятью и другими выделяемыми ей ресурсами. Многозадачность (multitasking) - это способность операционной системы выполнять несколько программ одновременно. В основе этого принципа лежит использование операционной системой аппаратного таймера для выделения отрезков времени (time slices) для каждого из одновременно выполняемых процессов.



Если эти отрезки времени достаточны малы, и машина не перегружена слишком большим числом программ, то пользователю кажется, что все эти программы выполняются параллельно.



32-разрядные версии Windows кроме многозадачности поддерживают еще и многопоточность (multithreading).Многопото́чность — способ выполнения процесса, при котором вычисления разбиваются на несколько потоков, выполняющихся «параллельно», т.е. без предписанного порядка во времени. При выполнении некоторых задач такое разделение может достичь более эффективного использования ресурсов вычислительной машины.

Все потоки выполняются в адресном пространстве процесса



Поток (thread) – это последовательность исполняемых команд. Процесс может состоять из единственного потока, а может содержать их несколько 



Итак, 

Многозадачная операционная система обеспечивает одновременное исполнение двух или более программ за счет выделения каждой из них процессорного времени. Многопотоковость же подразумевает использование под управлением операционной системы нескольких параллельных потоков вычислений, относящихся к одной прикладной программе.

В Win32, не процесс и не задача, а именно поток является базовым элементом механизма выполнения программ.

К достоинствам многопоточности в программировании можно отнести следующее:



Упрощение программы в некоторых случаях, за счет использования общего адресного пространства. 





Меньшие относительно процесса временны́е затраты на создание потока.



Повышение производительности процесса за счет распараллеливания процессорных вычислений и операций ввода/вывода.



При необходимости одновременного выполнения нескольких операций в рамках одной прикладной программы на реализацию каждой из них выделяется отдельный поток. Задача предоставления потоку необходимого процессорного времени возлагается исключительно на операционную систему.



При решении вопроса, какому потоку отдать предпочтение и сколько выделить ему времени, операционной системе приходится учитывать немало факторов. Недостаточно просто установить таймер, чтобы каждые несколько миллисекунд управление передавалось следующему очередному потоку.

Основным фактором, учитываемым при диспетчеризации, служит приоритет выполнения (execution priority) каждого потока. В Win32 каждому потоку присваивается свой приоритет - от 0 до 31; чем больше число, тем выше приоритет. Приоритет 31 резервируется под особенно критичные операции, например, прием данных в реальном режиме времени. Приоритет 0 назначается операционной системой самым второстепенным задачам, выполнение которых происходитв то время, когда нет других задач. Большинство потоков работают с приоритетом от 7 до 11



Каждые несколько миллисекунд диспетчер операционной системы пересматривает все работающие в системе потоки и выделяет процессорное время потоку с наивысшим приоритетом. Если потоков с одинаково высоким приоритетом несколько, то управление передается тому, который простаивает дольше других. В общем, в первую очередь всегда обрабатываются потоки с более высоким приоритетом, а потоки с низким приоритетом никогда не вытесняют потоки с более высоким.



Проблемы многопоточной архитектуры

Приведем рекомендации по архитектуре многопоточных программ.



Рекомендуется, чтобы первичный или главный (primary) поток программы создавал все окна и соответствующие им оконные процедуры, необходимые в программе, и обрабатывал все сообщения для этих окон. 





Всеостальные потоки должны быть вторичными (secondary), выполняющими фоновые задачи и не имеющими интерактивной связи с пользователем, кроме как через первичный поток. 



Рассмотрим проблему разделения ресурсов.



Потоки внутри отдельной программы являются частями одного процесса, поэтому они разделяют все ресурсы процесса, такие как память и открытые файлы. 





Поскольку потоки разделяют память, отведенную программе, то они разделяютглобальные переменные процесса и статические переменные своих функций потоков.





Однако у каждого потока есть свой собственный стек, и значит, автоматические переменные являются уникальными для каждого потока.





Каждый поток, также, имеет свое состояние процессора, которое сохраняется и восстанавливается при переключении между потоками. 



Итак,



Статические переменные процесса, как глобальные, так и локальные по отношению к функциям потоков, разделяются между потоками, поскольку они расположены в зоне памяти данных процесса. 





Автоматические переменные функций потоков (которые являются локальными по отношению к функции) - уникальны для каждого потока, т.к. они располагаются в стеке, а каждый поток имеет свой стек. 





Иногда бывает удобно использовать для двух и более потоков одну и ту же функцию, а статические данные использовать уникальные для каждого потока. Для каждого потока можно выделитьспециальную, локальную для него память, недоступную для других потоков.



Разработка, программирование и отладка сложного многопоточного приложения являются, естественно, самыми сложными задачами, с которыми приходится сталкиваться Windows-программисту. 



Поскольку в системе с вытесняющей многозадачностью поток может быть прерван в любой момент для переключения на другой поток, то может случайно произойти нежелательное взаимодействие между двумя потоками.





Одной из основных ошибок в многопоточных программах является так называемоесостояние гонки (race condition). Это случается, если программист считает, что один поток закончит выполнение своих действий, например, подготовку каких-либо данных, до того, как эти данные потребуются другому потоку. 



Для координации действий потоков операционных систем необходимы различные формы синхронизации.



Взаимоисключения (mutex, мьютекс) — это объект синхронизации, который устанавливается в особое сигнальное состояние, когда не занят каким-либо потоком. Только один поток владеет этим объектом в любой момент времени, отсюда и название таких объектов (от английского mute - молчаливый, приглушать звук) — одновременный доступ к общему ресурсу исключается. После всех необходимых действий мьютекс освобождается, предоставляя другим потокам доступ к общему ресурсу. 





Семафоры представляют собой доступные ресурсы, которые могут быть приобретены несколькими потоками в одно и то же время, пока пул ресурсов не опустеет. Тогда дополнительные потоки должны ждать, пока требуемое количество ресурсов не будет снова доступно. Семафоры очень эффективны, поскольку они позволяют одновременный доступ к ресурсам. 





Критические секции обеспечивают синхронизацию подобно мьютексам за исключением того, что объекты, представляющие критические секции, доступны в пределах одного процесса. События, мьютексы и семафоры также можно использовать в однопроцессном приложении, однако критические секции обеспечивают более быстрый и более эффективный механизм взаимно-исключающей синхронизации. Подобно мьютексам объект, представляющий критическую секцию, может использоваться только одним потоком в данный момент времени, что делает их крайне полезными при разграничении доступа к общим ресурсам.





События. События полезны в тех случаях, когда необходимо послать сообщение потоку, сообщающее, что произошло определенное событие. Например, при асинхронных операциях ввода и вывода из одного устройства, система устанавливает событие в сигнальное состояние когда заканчивается какая-либо из этих операций. Один поток может использовать несколько различных событий в нескольких перекрывающихся операциях, а затем ожидать прихода сигнала от любого из них. 





 Замечание.Использование семафоров может привести к другой распространенной ошибке, связанной с потоками, которая называется тупиком (deadlock). Это случается, когда два потока блокируют выполнение друг друга, а для того, чтобы их разблокировать, необходимо продолжить работу. 



Функции создания потока и его завершения

Для создания потокаможно использовать функцию из стандартной библиотеки языка С, определенную в файле process.h следующим образом и возвращающую дескриптор созданного потока:

 

unsigned long _beginthread( void( __cdecl *start_address )( void * ),

unsigned stack_size, void *arglist );

 



Через первый параметр start_address функции_beginthread передается адрес функции потока. После вызова функции _beginthreadкод функции потока, так же как и код любой другой функции, которая может быть вызвана из этой функции потока, выполняется одновременно с оставшимся кодом программы.





Последний параметр arglist функции _beginthread позволяет потоку, который создает этой функцией другой поток, передавать информацию этому потоку в виде 32-разрядной переменной. Обычно эта переменная является указателем на блок памяти (например, на структуру данных). Это дает возможность создающему и создаваемому потокам совместно владеть информацией без использования глобальных переменных (общая память потоков).





Второй параметр stack_size функции _beginthread служит для задания размера стека для потока. Если через этот параметр передать нулевое значение, то операционная система полагает размер стека для потока равным размеру стека главного потока.



 Замечание.Два и более потока могут использовать одну и ту же функцию процесса. В этом случае автоматические переменныефункции потока (хранящиеся в стеке) уникальны для каждого потока, все статические переменные этой функции потока являются общими для всех потоков, использующих эту функцию.

Завершение работы потока происходит при вызове функций:

 

void _endthread( void );

 



Но вызов этой функций не является строго необходимым, поскольку поток автоматически уничтожается при выходе из функции потока (при завершении ее выполнения), а также при завершении работы всего приложения. Однако функция _endthread является полезной при выходе из потока, находящегося глубоко в иерархии потоков обработки.



Для создания потока можно использовать и функцию стандартной библиотеки языка С _beginthreadex.С ее помощью можно задавать более разнообразные параметры создаваемого потока. Закрывать же поток, созданный этой функцией, следует при помощи функции _endthreadex.

Кроме рассматриваемых выше функцийбиблиотеки С для работы с потоками можно использовать и функции WinApi 32:CreateRemoteThread, CreateThread, ExitThread, GetExitCodeThread, GetThreadPriority, ResumeThread, SetThreadPriority.

 Замечание.Следует обратить внимание на изменения в make-файле, которые необходимо сделать для создания многопоточного приложения.

На этапе компиляции переменную CFLAGS нужно заменить переменной CFLAGSMT. Это та же переменная, но с добавлением флага _MT. Это приводит, в частности, к тому, что компилятор вставляет имя файла libcmt.lib вместо libc.lib. Эта информация используется компоновщиком.

При создании многопоточного приложения в среде MS-Visual C++необходимо при помощи пункта меню “Settings” внести изменения в опции проекта в диалоге “Project Settings”: 



·         закладка “C/C++” - в поле “Preprocessor definition” добавить флаг _MT; 





·         закладка “Link - в поле “Object/library modules” добавить библиотеку libcmt.lib, затем включить переключатель “Ignore all defaults libraries”.)



Примерные действия по созданию потока

Каждый поток имеет свою функцию – функцию потока. Пока выполнение этой функции не завершено, поток продолжает оставаться выполняемым. Эта функция должна быть объявлена следующим образом(в качестве имени потоковой функции выберем ThreadFun):