Потоки Windows: _beginthread против _beginthreadex против CreateThread C ++ - PullRequest
126 голосов
/ 01 декабря 2008

Что может быть лучше для создания потока, _beginthread, _beginthreadx или CreateThread?

Я пытаюсь определить, какие преимущества / недостатки у _beginthread, _beginthreadex и CreateThread. Все эти функции возвращают дескриптор потока во вновь созданный поток, я уже знаю, что CreateThread предоставляет немного дополнительной информации при возникновении ошибки (это можно проверить, вызвав GetLastError) ... но что я должен учитывать когда я использую эти функции?

Я работаю с приложением Windows, поэтому о кросс-платформенной совместимости уже не может быть и речи.

Я просмотрел документацию по MSDN и просто не могу понять, например, почему кто-то решил использовать _beginthread вместо CreateThread или наоборот.

ура!

Обновление: Хорошо, спасибо за всю информацию, я также прочитал в нескольких местах, которые я не могу назвать WaitForSingleObject(), если я использовал _beginthread(), но если я вызываю _endthread() в потоке, разве это не сработает? Что там за сделка?

Ответы [ 16 ]

2 голосов
/ 15 мая 2012

CreateThread() - это вызов Windows API, который не зависит от языка. Он просто создает объект OS-поток и возвращает HANDLE этому потоку. Все приложения Windows используют этот вызов для создания потоков. Все языки избегают прямого вызова API по очевидным причинам: 1. Вы не хотите, чтобы ваш код был специфичным для ОС 2. Перед вызовом API-интерфейса необходимо выполнить некоторые домашние операции: преобразовать параметры и результаты, выделить временное хранилище и т. Д.

_beginthreadex() - это оболочка C около CreateThread(), которая учитывает специфичность языка C. Он позволяет исходной однопоточной C-n-n работать в многопоточной среде, выделяя хранилище, специфичное для потока.

Если вы не используете CRT, вы не сможете избежать прямого звонка на CreateThread(). Если вы используете CRT, вы должны использовать _beginthreadex(), иначе некоторые строки CRT могут не работать должным образом до VC2005.

2 голосов
/ 23 сентября 2011

По сравнению с _beginthread, с _beginthreadex вы можете:

  1. Укажите атрибуты безопасности.
  2. Запуск потока в приостановленном состоянии.
  3. Вы можете получить идентификатор потока, который можно использовать с OpenThread.
  4. Возвращенный дескриптор потока гарантированно будет действительным, если вызов был успешный. Там вам нужно закрыть ручку с помощью CloseHandle.
  5. Возвращенный дескриптор потока можно использовать с API-интерфейсами синхронизации.

_beginthreadex очень похож на CreateThread, но первая - это реализация CRT, а вторая - вызов API Windows. Документация для CreateThread содержит следующую рекомендацию:

Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать _beginthreadex и _endthreadex функции для управления потоками вместо CreateThread и ExitThread; это требует использования многопоточной версии CRT. Если поток, созданный с использованием CreateThread, вызывает CRT, CRT может завершить процесс в условиях нехватки памяти.

1 голос
/ 18 октября 2012

CreateThread() - прямой системный вызов. Он реализован на Kernel32.dll, с которым, скорее всего, ваше приложение уже будет связано по другим причинам. Он всегда доступен в современных системах Windows.

_beginthread() и _beginthreadex() - функции-оболочки в среде выполнения Microsoft C (msvcrt.dll). Различия между двумя вызовами указаны в документации. Таким образом, он доступен, когда доступна среда выполнения Microsoft C или если ваше приложение статически связано с ней. Скорее всего, вы тоже будете ссылаться на эту библиотеку, если только вы не пишете в чистом API Windows (как я часто это делаю).

Ваш вопрос является последовательным и фактически повторяющимся. Как и многие API, в Windows API есть двойная и неоднозначная функциональность, с которой нам приходится иметь дело. Хуже всего то, что документация не проясняет проблему. Я полагаю, что семейство функций _beginthread() было создано для лучшей интеграции с другими стандартными функциями C, такими как манипуляции с errno. _beginthread(), таким образом, лучше интегрируется со средой выполнения C.

Несмотря на это, если у вас нет веских причин для использования _beginthread() или _beginthreadex(), вам следует использовать CreateThread(), главным образом потому, что вы можете получить на одну библиотечную зависимость меньше в вашем конечном исполняемом файле (а для MS CRT это действительно имеет значение немного). У вас также нет кода переноса вызова, хотя этот эффект незначителен. Другими словами, я считаю, что основная причина придерживаться CreateThread() заключается в том, что нет веских оснований для использования _beginthreadex() для начала. Функциональные возможности точно или почти одинаковы.

Одной из веских причин для использования _beginthread() было бы (как кажется, ложное), что объекты C ++ были бы должным образом развернуты / уничтожены, если был вызван _endthread().

0 голосов
/ 16 сентября 2016

В других ответах не обсуждается значение вызова функции времени выполнения C, которая оборачивает функцию Win32 API. Это важно при рассмотрении поведения блокировки загрузчика DLL.

Независимо от того, _beginthread{ex} выполняет какое-либо специальное управление потоками / волоконной памятью среды выполнения C, как обсуждаются в других ответах, оно реализовано в (при условии динамического связывания с средой выполнения C) библиотеки DLL, которая еще не загружена процессами.

Не безопасно звонить _beginthread* с DllMain. Я проверил это, написав DLL, загруженную с помощью функции Windows «AppInit_DLLs». Вызов _beginthreadex (...) вместо CreateThread (...) приводит к тому, что многие важные части Windows перестают функционировать во время загрузки, так как DllMain тупиковые точки входа, ожидающие снятия блокировки загрузчика для выполнения определенных задач инициализации.

Кстати, именно поэтому kernel32.dll имеет много перекрывающихся строковых функций, которые также выполняет среда выполнения C - используйте из DllMain, чтобы избежать такой же ситуации.

0 голосов
/ 04 мая 2015

Больше нет никакой разницы между ними.

Все комментарии об утечках памяти и т. Д. Основаны на очень старых версиях

0 голосов
/ 16 февраля 2014

Если вы читаете в ней книгу «Отладка приложения Windows» Джеффри Рихтера, он объясняет, что почти во всех случаях вы должны вызывать _beginthreadex вместо вызова CreateThread. _beginthread - это просто упрощенная оболочка для _beginthreadex.

_beginthreadex инициализирует некоторые внутренние компоненты CRT (C RunTime), которые не может выполнять API CreateThread.

Вследствие этого, если вы используете CreateThread API вместо _begingthreadex, вызовы функций CRT могут неожиданно вызвать проблемы.

Посмотрите этот старый журнал Microsoft From Richter.

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