Визуальное программирование и MFC

       

Создание рабочего потока


Для создания рабочего потока предназначена функция AfxBeginThreadбиблиотеки MFC:

CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

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

UINT pfnThreadProc(LPVOID pParam);

Значение параметра pParam функции AfxBeginThread передается потоковой функции в качестве параметра. Это 32-разрядное число может использоваться для любых целей.

Начальный приоритет потока указывается в параметре nPriority. Если этот параметр равен 0, то используются установки приоритета текущего (родительского) потока.

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

Параметр dwCreateFlags определяет состояние выполнения потока. Если данный параметр равен нулю, поток начинает выполняться немедленно. Если значение этого параметра равно CREATE_SUSPEND, то поток создается временно приостановленным, т.е. ожидающим запуска. Чтобы запустить такой поток, нужно вызвать функцию CWinThread::ResumeThread.

Параметр lpSecurityAttrs является указателем на набор атрибутов прав доступа, относящийся к данному потоку. Если этот параметр равен NULL, то набор атрибутов будет унаследован от родительского окна.

При успешном завершении функция AfxBeginThread возвращает указатель на объект потока, в противном случае возвращает ноль. Данный указатель необходимо сохранять, если впоследствии предполагается обращение из родительского потока к созданному потоку (например, для изменения приоритета или для временного приостановления потока).


Рассмотрим пример создания рабочего потока для однодокументного приложения example при обработке сообщения о выборе пользователем пункта меню “Start”. В качестве родительского потока выступает главный поток приложения. Рабочий поток после запуска осуществляет 100-кратный вывод некоторого изображения в окно приложения:

UINT MyThread(LPVOID pParam); // объявление функции потока // реализация метода класса CExampleView (класса обликов), // наследованного от базового CView из MFC. void CExampleView::OnStart() // обработка сообщения от меню { //Создать новый поток. Функция потока имеет имя MyThread, // в качестве параметра функции потока передается указатель // на текущее окно просмотра для вывода в него изображения AfxBeginThread(MyThread,this); } // определение функции потока UINT MyThread(LPVOID pParam) { // через параметр передается указатель на окно просмотра CExampleView *ptrView=(CExampleView *)pParam;

for(int i=0; i<100; i++) { CDC *dc=ptrView->GetDC(); // получить контекст отображения CRect r; ptrView->GetClientRect(&r); // получить клиентскую область окна dc->TextOut(rand()%r.Width(),rand()%r.Height(),"*",1); // вывод } return 0; }

Как уже упоминалось выше, поток выполняется до завершения своей потоковой функции. Поток может также “завершить сам себя” с помощью функции AfxEndThread библиотеки MFC. Параметр этого метода содержит статус завершения потока. Как правило, лучше давать потоку возможность нормально завершиться одновременно с потоковой функцией.

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


Содержание раздела