Или как не вызвать гнев ввода вывода… Сегодня речь пойдет о том как создавать потоки и работать с ними в программе, написанной на C/C++. Можно сказать, что практически исчерпывающую информацию можно найти на msdn, но печаль заключается в том, что врятли новичек, руководствуясь этим справочником в течении 10 минут сможет реализовать многопоточность. Как мне кажется, это займет минимум день. Ко всему прочему я также попытаюсь описать простейшую синхронизацию, благодаря которой не будет неприятных последствий при обращении с вводом/выводом.

yoda logo Многопоточное программирование

Итак, начнем пожалуй с используемых функций…

Самой основной функцией для реализации многопоточности является функция

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

в которой первый параметр lpThreadAttributes является аттрибутом защиты — для нас его можно смело положить в NULL. Второй параметр dwStackSize — это размер в байтах, выделяемый под стэк, если не знаете, смело пишите 0 — будет взят стандартный размер. Третий параметр  lpStartAddress — стартовый адрес потока. Можно сказать проще — это имя функции, которая будет работать как экземпляр потока. Т.е. для реализации многопоточности нам потребуется реализовать лишь одну функцию, а потом запускать CreateThreadс указанием ее имени. Четвертый параметр lpParameter - это указатель на параметр, передаваемый потоку. Пятый параметр (опции создания потока) dwCreationFlags установим в 0. Тогда поток запустится сразу после создания. Ну а последний lpThreadId — это идентификатор создаваемого потока.

Вторая замечательная функция, которая позволяет подождать, пока все потоки отработают, это функция

DWORD WINAPI WaitForMultipleObjects(
  __in  DWORD nCount,
  __in  const HANDLE *lpHandles,
  __in  BOOL bWaitAll,
  __in  DWORD dwMilliseconds
);

В ней первый параметр показывает, сколько потоков нужно ждать, второй параметр — это массив хэндлов от созданных потоков (то что возвращает CreateThread), третий параметр показывает, стоит ли ждать все, ну а четвертый указывает, каков таймаут. Мы, для удобства, будем ждать хоть всю жизнь, установив четвертый параметр в значение INFINITE.

Ну а третья и четвертая основные функции очень маленькие: это CloseHandle() и ExitThread(). Первая функция пинимает хэндл потока и закрывает его. Вторая функция вызывается в потоке и корректно его завершает. Её единственный параметр — код завершения (установим его в нуль).

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

Можно сказать что основы реализации многопоточности мы рассмотрели. Но все не так просто. Для того, чтобы не давать одновременно всем куда то ломится нужно реализовать синхронизацию. В примере я буду синхронизировать потоки через критические секции. Что нужно сделать для создания критической секции? Сначала нужно ее инициализировать, потом по мере необходимости входить и выходить, а затем удалить. Все это реализуют четыре функции. Единственный их входной параметр — это указатель на объявленную нами критическую секцию.

void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

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

#include 
#include 

CRITICAL_SECTION cs = {0};

typedef struct _TStartupInfo
{
        DWORD dwId;
}TStartupInfo;

DWORD WINAPI Thread(LPVOID p)
{
        TStartupInfo *si = (TStartupInfo *)p;

        EnterCriticalSection(&cs);
                printf("Thread %d get access\n",si->dwId);
        LeaveCriticalSection(&cs);

        free(si);

        ExitThread(0);
        return 0;
}

int main()
{
        const int k = 10;
        unsigned int i;

        InitializeCriticalSection(&cs);

        DWORD dwId;
        HANDLE hThread[k] = {0};
        for(i = 0;i
                      

Для передачи параметров здесь используется структура TStartupInfo. Таким образом можно передать не один, а несколько параметров. Каждый передаваемый параметр мы создаем в памяти, а уже в потоке при ненужности его удаляем.  Собственно вот и все, что я хотел рассказать.

tt twitter big4 Многопоточное программирование tt digg big4 Многопоточное программирование tt facebook big4 Многопоточное программирование tt gmail big4 Многопоточное программирование tt myspace big4 Многопоточное программирование tt reddit big4 Многопоточное программирование

Один комментарий на “Многопоточное программирование”

Оставить комментарий

CAPTCHA изображение
Обновить изображение
*

RSS-подписка NIG Twitter-подписка NIG

Метки
Друзья
Блог линуксоида Программы для диагностики компьютера
Супер Pixel
Убивалка флешаБэкконект шелл. Часть вторая.Бэкконект шелл. Начало.НАМ для деления чиселПростая арифметикаПередача файлов. Часть третья. Клиент.Dll injectionСканер портовКодировка текста в BMPРухнул на два дняПередача файлов. Часть вторая. Сервер.Поворот и BMPCRC32 суммаBMP форматфайловые вирусыассемблер, строкиАссемблер и матрицапримеры ассемблерМногопоточное программированиеАрхитектура клиент — серверРаздача ICQПишем шуткупишем паукаПривет от ДжеймсаОбход firewallЗагрузка картинок на Gyazo, прямо из ThunarКейлоггер 3Плюшки в контекстном меню Thunarc по сетиКейлоггер 2КейлоггерСкачать Ассемблер!VirusCheckerОтморозки мешают жить ?! Не проблемма !Cкрипты для взлома аккаунтов QIPWinAPI. Работа с файлами. Часть третья. ЧтениеDlink exploitБрут сайта etxt.ruКрасивая раскладка клавиатуры в GnomeМои безделушки на PerlКак запускать Perl скрипты под WindowsБрутфорс партнёрки ZipCoinПарсер upwap.ruИзменения в блогеЧудо ЗаливалкаСкрипт для загрузки файлов на Zalil.ruЯндекс «чоткий» поисковик!WinAPI. Работа с файлами. Часть вторая. ЗаписьWinAPI. Работа с файлами. Часть первая. ПоискПолучение MD5 хеша средствами C++Что нам стоить letitfile.com забрутить?WarCraft III запуск под LinuxЭнтропия файлаWinsock и C++. Мини прокси. Часть |\\/. Завершающая.Перепилил чекер для 4gameЧекер акаунтов YoupornCMailSend v 1.1. Отправка почы без проблемСлучайные числаWinsock и C++. Часть |||. smtp монстр.Брутфорс LetitFile.comИспользование X-Forwarded-For, для обмана веб-сервера, подмена IP подручными средствамиДело было вечером, делать было нечего…Мысли о аудио сервереПарсер ников из твиттераКонец школоло…Perl+Linux. Заметка первая (Удобный Paste bin).Бэкконект шелл.E-MAIL + winsocket + Cpp. Сложно?winsock и C++. Часть ||. Атака клоунов.C++ резолвинг адресаPerl, анализ HTML кода и определение CMSМатематика в C++winsock и C++