Пользователь

Добро пожаловать,

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

Меню сайта




Ваше мнение
Как вы оцените наш сайт?

Замечательный
Хороший
Обычный
Плохой
Отвратительный


Результаты
Другие опросы

Всего голосов: 846
Комментарии: 10


Наши партнеры



Статистика




Programming books  Download software  Documentation  Scripts  Content Managment Systems(CMS)  Templates  Icon Sets  Articles  Contacts  Voting  Site Search




Статьи и обзоры



C++ Потоки в Win32

Подборка статей по программированию на языке C++ и в средах разработки Visual C+ и C++ Builder. Даже если вы считаете себя профессионалом, вы все равно найдете здесь для себя что-то новое. Опытом делятся профессионалы. Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах. На практике это означает, что потоки исполняют код и манипулируют данными в адресном пространстве процесса. Если два или более потока выполняются внутри одного процесса, они делят одно адресное пространство.
Любой поток (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, однако при этом не разрушит и не очистит стек потока. Стек будет существовать, пока не завершится процесс, которому принадлежит поток. При задачах, постоянно создающих и уничтожающих потоки, это приводит к потере памяти внутри процесса.

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

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

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



  • Нет комментариев. Почему бы Вам не оставить свой?
    Вы не можете отправить комментарий анонимно, пожалуйста войдите или зарегистрируйтесь.
    Внимание! Если у вас не получилось найти нужную информацию, используйте рубрикатор или воспользуйтесь поиском


    .



    Статьи и обзоры С++ Visual C++ C++ Потоки в Win32 Потоки всегда создаются контексте какого-либо процесса вся их жизнь проходит только его границах На практике это означает что потоки исполняют код манипулируют данными адресном пространстве Если два или более потока выполняются внутри одного они делят одно адресное пространство Любой поток thread состоит из двух компонентов объекта ядра через который ОС управляет потоком Там же хранится статистическая