Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 8 мая!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

ПРОГРАММИРОВАНИЕ НА C и С++



Слушай, дружище, зачем так мучиться с этим языком С++, ты ведь не Билл Гейтс. Возьми тот же Python и программируй, он кроссплатформенный, под Windows тоже работает. Я сам давно заметил: то что на Си пишешь в страницу кода, на питоне решается в одну-две строки. При том, питон намного проще, я его сам недавно изучил по видеокурсу вот этому. Кстати, автор отлично там объясняет. Буквально день-два и уже будешь писать на нём, чего не скажешь про сложный С++.
Метод класса в новом потоке
A: (Leprecon)
Оригинальная ссылка: нету

Иногда функциональности глобальной функции или статического метода класса не хватает при запуске нового потока. С методом класса новый поток не создашь. Компилятор выдаст вот такую ошибку:
error C2664: 'CreateThread' : cannot convert parameter 3 from 'unsigned long (__thiscall CMyClass::*)(void *)' to 'unsigned long (__stdcall *)(void *)'
Функцию __thiscall просто так к __stdcall не приведешь, ведь для метода передается еще указатель на класс. Но если немного схитрить, то это можно обойти. Вместо метода мы создадим поток со статической функцией. А в качестве данных, передадим указатель на структуру, в которую положим:
1. Указатель на экземпляр класса.
2. Указатель на метод класса.
3. Указатель на дествительные данные для метода.
Когда новый поток запустится, то статическая функция, зная указатель на класс и нужный метод, запустит этот метод в новом потоке.
class CMyClass;
 
 typedef DWORD (CMyClass::*LPTHREAD_METHOD)(LPVOID pParam);
 
 
 
 // Структура параметров для статической функции.
 
 typedef struct STARTUP_PARAM
 
 {
 
     CMyClass*        pClass;
 
     LPTHREAD_METHOD    pMethod;
 
     LPVOID            pParam;
 
 } *LPSTARTUP_PARAM;
 
 
 
 // Объявление класса.
 
 class CMyClass
 
 {
 
 public:
 
     // Метод, который мы хотели бы запустить в новом потоке.
 
     DWORD    Process            (LPVOID pParam);
 
 
 
     // Функция, которая создает новый поток.
 
     HANDLE    StartThread        (LPTHREAD_METHOD pMethod, LPVOID pParam,
 
                              LPDWORD pdwThreadID = NULL,
 
                              LPSECURITY_ATTRIBUTES pSecurity = NULL ,
 
                              DWORD dwStackSize = 0 ,
 
                              DWORD dwFlags = 0);
 
 protected:
 
     // Статическая функция, которая запустит метод.
 
     static  DWORD StartFunc    (LPSTARTUP_PARAM pStartup);
 
 };
 
 
 
 // В этом методе можно реализовать вычисления, которые вам нужны.
 
 DWORD CMyClass::Process(LPVOID pParam)
 
 {
 
     Sleep(1000);
 
     return 0;
 
 }
 
 
 
 HANDLE CMyClass::StartThread(LPTHREAD_METHOD pMethod, LPVOID pParam,
 
                              LPDWORD pdwThreadID /* = NULL */,
 
                              LPSECURITY_ATTRIBUTES pSecurity /* = NULL */,
 
                              DWORD dwStackSize /* = 0 */,
 
                              DWORD dwFlags /* = 0 */)
 
 {
 
     // Создаем структуру и упаковываем данные для статической функции.
 
     LPSTARTUP_PARAM pStartup = new STARTUP_PARAM;
 
     pStartup->pClass    = this;
 
     pStartup->pMethod    = pMethod;
 
     pStartup->pParam    = pParam;
 
 
 
     // Создаем новый поток.
 
     return CreateThread(pSecurity, dwStackSize, (LPTHREAD_START_ROUTINE)StartFunc, pStartup, dwFlags, pdwThreadID);
 
 }
 
 
 
 // В новом потоке вначале вызывается функция CMyClass::StartFunc(...)
 
 // А она запускает наш метод.
 
 DWORD CMyClass::StartFunc(LPSTARTUP_PARAM pStartup)
 
 {
 
     // Распаковываем данные в новом потоке.
 
     // Получаем указатель на класс и на метод класса.
 
     CMyClass* pClass        = pStartup->pClass;
 
     LPTHREAD_METHOD pMethod = pStartup->pMethod;
 
     LPVOID pParam            = pStartup->pParam;
 
 
 
     // Запускаем метод класса в новом потоке.
 
     DWORD dwResult = (pClass->*pMethod)(pParam);
 
 
 
     // Удаляем временные данные и возвращаем код возврата из нового потока.
 
     delete pStartup;
 
     return dwResult;
 
 }
 
 
Подробнее остановимся на функции CMyClasss::StartThread
Функция создает новый поток в виртуальном адресном пространстве вызывающего процесса.
HANDLE CMyClass::StartThread(
 
     LPTHREAD_METHOD pMethod, LPVOID pParam,
 
     LPDWORD pdwThreadID /* = NULL */,
 
     LPSECURITY_ATTRIBUTES pSecurity /* = NULL */,
 
     DWORD dwStackSize /* = 0 */,
 
     DWORD dwFlags /* = 0 */
 
 );
Эта функция аналогична функции Win32 API
HANDLE CreateThread(
 
     LPSECURITY_ATTRIBUTES lpThreadAttributes,
 
     SIZE_T dwStackSize,
 
     LPTHREAD_START_ROUTINE lpStartAddress,
 
     LPVOID lpParameter,
 
     DWORD dwCreationFlags,
 
     LPDWORD lpThreadId
 
 );
Параметры:
    pMethod [in] указатель на метод класса, для вызова в новом потоке.
    pParam [in] указатель на данные для нового потока.
    pdwThreadID [out] указатель на переменную, которая получит идентификатор потока.
    pSecurity [in] указатель на структуру SECURITY_ATTRIBUTES, которая устанавливает, может ли дочерний процесс унаследовать возвращаемый хендл потока. Если pSecurity равно NULL, хендл не может быть унаследован. Windows NT/2000/XP: Поле lpSecurityDescriptor структуры, устанавливает атрибуты безопастности для нового потока. Если pSecurity равно NULL, потоку даются атрибуты по умолчанию.
    dwStackSize [in] Изначальный размер стека, в байтах. Система округлит это значение до ближайшей страницы. Если значение равно нулю, новый поток возьмет размер по умолчанию.
    dwCreationFlags [in] Флаги для создания потока. Если установлен флаг CREATE_SUSPENDED, поток создается в приостановленном состоянии и не будет запущен, пока не будет вызвана фугкция ResumeThread. Если значение равно нулю, то поток запустится сразу после создания.
Результат:
    В случае успеха, возвратится хендл созданного потока.
    В случае неудачи, возвратится NULL.

Пример:
CMyClass MyClass;
 
 
 
 char* pStr = new char [6];
 
 strcpy(pStr, "Hello");
 
 
 
 DWORD dwThreadID;
 
 HANDLE hThread = MyClass.StartThread(CMyClass::Process, (LPVOID)pStr, &dwThreadID);
Метод CMyClass::Process, запустится в новом потоке и значение this будет равно указателю на класс MyClass.

Примечание: При работе с классами в разных потоках не забывайте о синхронизации.

Если есть какие-то замечания, предложения или что-то еще, то пишите:
leprecon@pisem.net.


<< ВЕРНУТЬСЯ В ПОДРАЗДЕЛ

<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ




Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS