(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

C++ потоки в WIN32

Источник: coders-library
admin

Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах. На практике это означает, что потоки исполняют код и манипулируют данными в адресном пространстве процесса. Если два или более потока выполняются внутри одного процесса, они делят одно адресное пространство.
Любой поток (thread) состоит из двух компонентов:

  • объекта ядра, через который ОС управляет потоком. Там же хранится статистическая информация о потоке.
  • Стека потока, который содержит параметры всех функций и локальные переменные, необходимые потоку для выполнения кода.

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

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

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

    Создание потока.

    Первичный поток, который присутствует в программе, начинает свое выполнение с главной функции потока типа WinMain.

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

    Код
    DWORD WINAPI ThreadFunc(PVOID pParam)
    {
    DWORD dwResult = 0;
    .........
    return dwResult;
    }

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

    Когда поток закончит свое исполнение, он вернет управление системе, память, отведенная под его стек, будет освобождена, а счетчик пользователей его объекта ядра "поток" уменьшится на 1. Когда счетчик обнулится, этот объект ядра будет разрушен.

    Для создания своего потока необходимо использовать функцию CreateThread:

    Код
    HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
    DWORD dwStackSize, 
    LPTHREAD_START_ROUTINE lpStartAddress, 
    LPVOID lpParameter, 
    DWORD dwCreationFlags, 
    LPDWORD lpThreadId);

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

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

    CreateThread - это Windows-функция, создающая поток. Если вы пишете код на С/С++ не вызывайте ее. Вместо нее Вы должны использовать _beginthreadex из библиотеки Visual C++. Почему это так важно в наших следующих выпусках.

    Параметры функции CreateThread.

    LpThreadAttributes - является указателем на структуру LPSECURITY_ATTRIBUTES. Для присвоения атрибутов защиты по умолчанию, передавайте в этом параметре NULL.

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

    LpStartAddress - указатель на адрес входной функции потока.

    LpParameter - параметр, который будет передан внутрь функции потока.

    DwCreationFlags - принимает одно из двух значений: 0 - исполнение начинается немедленно, или CREATE_SUSPENDED - исполнение приостанавливается до последующих указаний.

    LpThreadId - Адрес переменной типа DWORD в который функция возвращает идентификатор, приписанный системой новому потоку.

    Завершение потока

    Поток можно завершит четырьмя способами:
  • функция потока возвращает управление (рекомендуемо);
  • поток самоуничтожается вызовом функции ExitThread;
  • другой поток процесса вызывает функцию TerminateThread;
  • завершается процесс, содержащий данный поток.

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

    Функция потока, возвращая управление, гарантирует корректную очистку всех ресурсов, принадлежащих данному потоку. При этом:

  • любые С++ объекты, созданные данным потоком, уничтожаются соответствующими деструкторами;
  • система корректно освобождает память, которую занимал стек потока;
  • система устанавливает код завершения данного потока. Его функция и возвращает;
  • счетчик пользователей данного объекта ядра (поток) уменьшается на 1.

    При желании немедленно завершить поток изнутри используют функцию ExitThread(DWORD dwExitCode).

    При этом освобождаются все ресурсы ОС, выделенные данному потоку, но С С++ ресурсы (например, объекты классов С++) не очищаются. Именно поэтому не рекомендовано завершать поток, используя эту функцию.

    Если же вы ее использовали, то кодом возврата потока будет тот параметр, который вы передадите в данную функцию.

    Как и для CreateThread для библиотеки Visual C++ существует ее аналог _endthreadex, который и стоит использовать. Об причинах в следующем выпуске.

    Если появилась необходимость уничтожить поток снаружи, то это моет сделать функция TeminateThread.

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

    При завершении процесса происходит следующее.

    Завершение потока происходит принудительно. Деструкторы объектов не вызываются, и т.д. и т.д.

    При завершении потока по такой причине, связанный с ним объект ядра (поток) не освобождается до тех пор, пока не будут закрыты все внешние ссылки на этот объект.

  • Ссылки по теме


     Распечатать »
     Правила публикации »
      Написать редактору 
     Рекомендовать » Дата публикации: 05.07.2012 
     

    Магазин программного обеспечения   WWW.ITSHOP.RU
    Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
    Microsoft 365 Business Standard (corporate)
    Microsoft 365 Apps for business (corporate)
    Microsoft Windows Professional 10, Электронный ключ
    Microsoft 365 Business Basic (corporate)
     
    Другие предложения...
     
    Курсы обучения   WWW.ITSHOP.RU
     
    Другие предложения...
     
    Магазин сертификационных экзаменов   WWW.ITSHOP.RU
     
    Другие предложения...
     
    3D Принтеры | 3D Печать   WWW.ITSHOP.RU
     
    Другие предложения...
     
    Новости по теме
     
    Рассылки Subscribe.ru
    Информационные технологии: CASE, RAD, ERP, OLAP
    Безопасность компьютерных сетей и защита информации
    Новости ITShop.ru - ПО, книги, документация, курсы обучения
    Программирование на Microsoft Access
    CASE-технологии
    Все о PHP и даже больше
    Delphi - проблемы и решения
     
    Статьи по теме
     
    Новинки каталога Download
     
    Исходники
     
    Документация
     
     



        
    rambler's top100 Rambler's Top100