асист .
каф . КСМ Ковальов М.П., ст.гр.
КСМ-06-2 Погорелова А.С.
Криворожский технический университет, Украина
Использование потоков в C++
Эта статья посвящена
разработке программного обеспечения с использованием потоков в с++. Все
рассмотренные в статье примеры используют язык C++ и компилируются с помощью
Microsoft Visual Studio.NET.
Поток исполнения
программы — это способ добиться параллельности ее работы. Если говорится, что
программа содержит два потока, значит, существует два набора инструкций, выполняющихся
параллельно или псевдопараллельно. Почему псевдопараллельно? Потому что в
системе с одним процессором просто невозможно одновременно выполнять две
команды. В таких случаях обычно используется переключение между потоками, т.е.
операционная система сама делит по своим внутренним предпочтениям процессорное
время на запущенные потоки. С широким использованием многоядерных или
многопроцессорных систем стало еще важнее распараллеливать потоки исполнения
программы.
Одним из самых
распространенных вариантов применения этой технологии является «скидывание» в
отдельный поток какой-нибудь достаточно продолжительной операции, для того
чтобы иметь возможность корректно реагировать на события пользовательского
интерфейса в главном потоке программы. Если вы запустили какую-либо операцию в
программе, а она не реагирует на ваши действия, то скорее всего в данном случае
существует только один главный поток. [1]
Использование потоков в
программировании — огромный пласт как теоретического, так и практического
знания. В этот раз мы остановимся на применении потоков в C++ и инкапсуляции
потоков в классе.
К сожалению, невозможно без дополнительных ухищрений
использовать в качестве функции потока функции—члены класса. Во-первых, обычно
для функции, содержащей тело потока, задана вполне конкретная сигнатура,
которую программист не может изменить. Вторым камнем преткновения является то,
что при вызове функции—члена в C++ используется неявный параметр — указатель на
экземпляр класса. [2]
На самом деле никто не запрещает применять
простую функцию в стиле Си. Однако такой подход лишит нас прозрачности и
легкости понимания кода.
Первый способ, который можно придумать, — использование
статической функции — члена класса с явным параметром, ссылкой на объект этого
класса. Такая функция будет «заглушкой» для вызова «настоящей» функции-члена
после явного преобразования параметра к объекту класса.
class
PThreadedAdapter { protected: HANDLE workerThread; bool workerLive, isThreadRunning; static DWORD WINAPI
ThreadStub(LPVOID lParameter) {
((PThreadedAdapter*)lParameter)->ThreadProc(); return 0; } virtual void ThreadProc(void)=0; } //Поток создается следующим образом: ::CreateThread(NULL,0,(LPTHREAD_START_
ROUTINE)PThreadedAdapter::ThreadStub,
this, 0, &dwWorkerID); |
Функция—член класса
ThreadProc должна будет содержать в себе то, что поток будет выполнять, т.е.
для применения этого «трюка» требуется создать новый класс, сделать описанный
PThreadedAdapter родительским для него и реализовать чисто виртуальную функцию
ThreadProc. В функции ThreadProc нужно установить «места прерывания» и
проверять в них переменную isRunning. Если isRunning становится false, то
необходимо корректно завершить работу и установить workerLive в false. Это
сообщит родительскому потоку, что потоковая функция успешно закончила свою
работу. [2]
Для удобства добавим еще функции Start и
Stop, которые, как видно из их имен, будут запускать и останавливать поток,
встроенный в наш класс.
void
PThreadedAdapter::Start(void) { workerLive = true; // Если будет false, то поток сразу остановится DWORD dwWorkerID; workerThread = ::CreateThread(NULL,0, (LPTHREAD_START_ROUTINE PThreadedAdapter::ThreadStub, this, 0, &dwWorkerID); if(!workerThread) { // Запустить не удалось workerLive = false; isRunning = false; } } void PThreadedAdapter::Stop() { workerLive = false; while(isRunning) { Sleep(waitTime); } } |
Выводы
Windows
поддерживает потоки, которые планируются независимо друг от друга, но разделяют
адресное пространство и ресурсы одного и того же процесса. Потоки даю
программисту возможность упростить программу и использовать параллелизм
выполнения задач для повышения производительности приложения. Потоки могут
обеспечить лучшую работу приложения даже в однопроцессорных системах.[3]
Литература
3. Джонсон
М. Харт. Системное программирование в среде Windows, 3-е издание.: Пер. с англ.
–М.: Издательский дом «Вильямс», 2005. -592с.ил. –Парал.тит.англ.