асист|. каф|. КСМ Ковальов М.П., ст.гр. КСМ-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]

Литература

1.     http://www.osp.ru

2.     http://www.codenet.ru

3.     Джонсон М. Харт. Системное программирование в среде Windows, 3-е издание.: Пер. с англ. –М.: Издательский дом «Вильямс», 2005. -592с.ил. –Парал.тит.англ.