Какой лучший способ начать обсуждение _beginthread
, _beginthreadx
или CreateThread
?
Я пытаюсь определить, в чем преимущества / недостатки _beginthread
, _beginthreadex
и CreateThread
. Все эти функции возвращают дескриптор потока для вновь созданного потока, я уже знаю, что CreateThread предоставляет небольшую дополнительную информацию при возникновении ошибки (ее можно проверить, позвонив GetLastError
) ... но какие вещи я должен учитывать, когда я ' м используя эти функции?
Я работаю с приложением Windows, поэтому о кроссплатформенной совместимости уже не может быть и речи.
Я просмотрел документацию по msdn и просто не могу понять, например, почему кто-то решил использовать _beginthread вместо CreateThread или наоборот.
Ура!
Обновление: хорошо, спасибо за всю информацию, я также прочитал в нескольких местах, которые я не могу назвать, WaitForSingleObject()
если бы использовал _beginthread()
, но если я позвоню _endthread()
в поток, не должно ли это работать? В чем дело?
источник
Ответы:
CreateThread()
- это необработанный вызов Win32 API для создания еще одного потока управления на уровне ядра._beginthread()
&_beginthreadex()
- это вызовы библиотеки времени выполнения C, которые вызываютсяCreateThread()
за кулисами. ПослеCreateThread()
возврата_beginthread/ex()
занимается дополнительной бухгалтерией, чтобы сделать библиотеку времени выполнения C пригодной для использования и согласованной в новом потоке.В C ++ вам почти наверняка следует использовать,
_beginthreadex()
если вы вообще не будете связываться с библиотекой времени выполнения C (также известной как MSVCRT * .dll / .lib).источник
_begin
подпрограммы как внутренние вызовы иCreateThread
должна была быть функцией API, которую все вызовут. Другое возможное объяснение заключается в том, что MS имеет долгую и славную историю игнорирования стандарта и принятия очень плохих решений по поводу именования вещей._begin
функции начинаются с подчеркивания , потому что Microsoft начал более внимательно следить за развитием стандарта. В среде выполнения C имена с подчеркиванием зарезервированы для реализации (и реализация может задокументировать их для использования конечным пользователем, как в случае с ними).beginthreadex()
это имя, которое разрешено использовать пользователю. Если среда выполнения C использовала его, то он мог бы конфликтовать с символом конечного пользователя, который пользователь имел законное право ожидать использования. Обратите внимание, что API Win32 не являются частью среды выполнения C и используют пространство имен пользователя.CreateThread
и вызовами CRT_beginthread/ex
, и при вызове CRT в потоке его всегда следует создавать с помощью_beginthread/ex
. Если вы этого не сделаете, утечек памяти может не быть. Но вы наверняка не получите правильную инициализацию среды с плавающей запятойCreateThread
, например, при вызове . Там же еще : «Если поток создается с помощью CreateThread вызывает CRT, ЭЛТ может завершить процесс в условиях низкой памяти.»Есть несколько различий между
_beginthread()
и_beginthreadex()
._beginthreadex()
был сделан, чтобы действовать больше какCreateThread()
(по обоим параметрам и как он себя ведет).Как упоминает Дрю Холл , если вы используете среду выполнения C / C ++, вы должны использовать
_beginthread()
/_beginthreadex()
вместо,CreateThread()
чтобы среда выполнения имела возможность выполнить инициализацию собственного потока (настройка локального хранилища потока и т. Д.).На практике это означает, что это
CreateThread()
практически никогда не должно использоваться напрямую в вашем коде.В документах MSDN для
_beginthread()
/_beginthreadex()
есть довольно много деталей о различиях - одним из наиболее важных является то, что, поскольку дескриптор потока для потока, созданного с помощью,_beginthread()
автоматически закрывается CRT, когда поток завершается, "если поток, созданный _beginthread, завершается быстро дескриптор, возвращаемый вызывающей стороне _beginthread, может оказаться недопустимым или, что еще хуже, указывать на другой поток ".Вот что
_beginthreadex()
говорят комментарии к источнику CRT:Обновление в январе 2013 г .:
CRT для VS 2012 имеет дополнительный бит инициализации, выполняемый в
_beginthreadex()
: если процесс является «упакованным приложением» (если из него возвращается что-то полезноеGetCurrentPackageId()
), среда выполнения инициализирует MTA во вновь созданном потоке.источник
CreateThread
себя Правым становятся все меньше и меньше.В общем, правильнее всего позвонить
_beginthread()/_endthread()
(илиex()
варианты). Однако, если вы используете CRT как .dll, состояние CRT будет правильно инициализировано и уничтожено, поскольку CRTDllMain
будет вызываться сDLL_THREAD_ATTACH
иDLL_THREAD_DETACH
при вызовеCreateThread()
и /ExitThread()
или возврате соответственно.DllMain
Код CRT можно найти в каталоге установки для VS под VC \ элт \ SRC \ crtlib.c.источник
Это код, лежащий в основе
_beginthreadex
(см.crt\src\threadex.c
):Остальная часть
_beginthreadex
инициализирует структуру данных для каждого потока для CRT.Преимущество использования
_beginthread*
заключается в том, что ваши CRT-вызовы из потока будут работать правильно.источник
Вы должны использовать
_beginthread
или_beginthreadex
разрешить библиотеке времени выполнения C выполнять собственную инициализацию потока. Это необходимо знать только программистам на C / C ++, так как теперь они должны знать правила использования собственной среды разработки.Если вы используете,
_beginthread
вам не нужно звонить, такCloseHandle
как RTL сделает за вас. Вот почему вы не можете ждать ручки, если вы использовали_beginthread
. Также_beginthread
приводит к путанице, если функция потока завершается немедленно (быстро), поскольку запускающий поток может удерживать недопустимый дескриптор потока для только что запущенного потока._beginthreadex
дескрипторы могут использоваться для ожидания, но также требуют явного вызоваCloseHandle
. Это часть того, что делает их безопасными для использования с ожиданием. Есть еще одна проблема, чтобы сделать его полностью надежным - это всегда запускать поток приостановленным. Проверка успеха, запись дескриптора и т. Д. Поток возобновления. Это необходимо для предотвращения завершения потока до того, как запускающий поток сможет записать свой дескриптор.Лучше всего использовать
_beginthreadex
, запуск приостановлен, затем возобновить после дескриптора записи, ожидание дескриптора в порядке,CloseHandle
необходимо вызвать.источник
CreateThread()
использовались для утечки памяти при использовании любых функций CRT в вашем коде._beginthreadex()
имеет такие же параметрыCreateThread()
и более универсален, чем_beginthread()
. Так что рекомендую использовать_beginthreadex()
.источник
CreateThread
это никогда не происходит утечка памяти. Это скорее CRT, когда вызывается из потока, который не был должным образом инициализирован.Относительно вашего обновленного вопроса: «Я также читал в нескольких местах, которые я не могу назвать,
WaitForSingleObject()
если бы использовал_beginthread()
, но если я вызываю_endthread()
в потоке, это не должно работать?»В общем, вы можете передать дескриптор потока
WaitForSingleObject()
(или другим API, ожидающим дескрипторов объекта) для блокировки, пока поток не завершится. Но дескриптор потока, созданный с помощью_beginthread()
, закрывается при_endthread()
вызове (что может быть сделано явно или неявно во время выполнения, когда процедура потока возвращается).Проблема описана в документации для
WaitForSingleObject()
:источник
Глядя на сигнатуры функций,
CreateThread
почти идентично_beginthreadex
._beginthread
,_beginthreadx
противCreateThread
Замечания по здесь говорят ,
_beginthread
можно использовать либо__cdecl
или__clrcall
соглашение о вызове в качестве начальной точки, и_beginthreadex
могут использовать либо__stdcall
или__clrcall
для начальной точки.Я думаю, что любые комментарии, сделанные людьми по
CreateThread
поводу утечек памяти, сделаны более десяти лет назад, и, вероятно, их следует игнорировать.Интересно, что обе
_beginthread*
функции на самом деле вызываютсяCreateThread
изнутриC:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src
на моей машине.источник
beginthreadex
дает вам веткуHANDLE
для использованияWaitForSingleObject
и друзей.beginthread
не делает. Не забудьте,CloseHandle()
когда закончите. Настоящий ответ - использоватьboost::thread
или скоро использовать класс потоков C ++ 09.источник
По сравнению с
_beginthread
, с_beginthreadex
вы можете:OpenThread
.CloseHandle
.Он
_beginthreadex
очень похожCreateThread
, но первый является реализацией CRT, а второй - вызовом Windows API. В документации по CreateThread есть следующие рекомендации:источник
_beginthreadex
. Вы можете преобразовать результатuintptr_t
возврата из обеих функций вHANDLE
._beginthread
ручка закрывается при выходе. Таким образом, вы не можете надежно использовать дескриптор с API синхронизации или получить идентификатор потока до тех пор, пока не используете другой способ синхронизации и дублирования дескриптора. Но тогда это_beginthreadex
делается за вас.CreateThread()
когда-то было нет-нет, потому что CRT неправильно инициализировал / очищал. Но это уже история: теперь можно (используя VS2010 и, вероятно, несколько версий назад) вызывать,CreateThread()
не нарушая CRT.Вот официальное подтверждение от MS . В нем указано одно исключение:
Однако с точки зрения консистенции я лично предпочитаю продолжать использовать
_beginthreadex()
.источник
CreateThread()
это вызов Windows API, не зависящий от языка. Он просто создает объект ОС - поток и возвращает HANDLE этому потоку. Все приложения Windows используют этот вызов для создания потоков. Все языки избегают прямого вызова API по очевидным причинам: 1. Вы не хотите, чтобы ваш код был специфичным для ОС 2. Вам нужно немного поработать перед вызовом, подобным API: преобразовать параметры и результаты, выделить временное хранилище и т. Д._beginthreadex()
- это оболочка C,CreateThread()
которая учитывает специфичность C. Он позволяет исходным однопоточным C f-ns работать в многопоточной среде, выделяя хранилище для конкретных потоков.Если вы не используете CRT, вам не избежать прямого звонка
CreateThread()
. Если вы используете CRT, вы должны использовать,_beginthreadex()
иначе некоторые строки f-n CRT могут не работать должным образом до VC2005.источник
CreateThread()
это прямой системный вызов. Он реализован, наKernel32.dll
котором, скорее всего, ваше приложение уже будет связано по другим причинам. Он всегда доступен в современных системах Windows._beginthread()
и_beginthreadex()
являются функциями оболочки в Microsoft C Runtime (msvcrt.dll
). Различия между двумя вызовами указаны в документации. Таким образом, он доступен, когда доступна среда выполнения Microsoft C или если ваше приложение статически связано с ней. Скорее всего, вы также будете связываться с этой библиотекой, если только вы не кодируете чистый Windows API (как я лично часто это делаю).Ваш вопрос логичный и часто повторяющийся. Как и многие другие API, в Windows API есть повторяющиеся и неоднозначные функции, с которыми нам приходится иметь дело. Хуже всего то, что документация не проясняет проблему. Я полагаю, что
_beginthread()
семейство функций было создано для лучшей интеграции с другими стандартными функциями C, такими как манипуляции сerrno
._beginthread()
таким образом лучше интегрируется со средой выполнения C.Несмотря на это, если у вас нет веских причин для использования
_beginthread()
или_beginthreadex()
, вам следует использоватьCreateThread()
, в основном потому, что вы можете получить на одну библиотечную зависимость меньше в вашем конечном исполняемом файле (а для MS CRT это имеет немного значение). У вас также нет кода оболочки вокруг вызова, хотя этот эффект незначителен. Другими словами, я считаю, что основная причина, по которойCreateThread()
стоит придерживаться этого правила, заключается в том, что_beginthreadex()
для начала нет веской причины . Функциональные возможности в точности или почти одинаковы.Одной из веских причин для использования
_beginthread()
было бы (что кажется ложным), что объекты C ++ будут должным образом развернуты / уничтожены, если они_endthread()
были вызваны.источник
CreateThread
- это вызов Windows API для создания потока. Если вы используете CRT (потому что вы программируете на C или C ++), вам следует создавать потоки, используя_beginthread[ex]
вызовы CRT (которые вызываютCreateThread
в дополнение к выполнению необходимой инициализации CRT). Наиболее важное различие между_beginthread
и бывшим вариантом: первый сохраняет право собственности на дескриптор собственного потока, а второй передает право собственности вызывающему.msvcrt.dll
это не библиотека времени выполнения C! См. Blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273В других ответах не обсуждаются последствия вызова функции времени выполнения C, которая обертывает функцию Win32 API. Это важно при рассмотрении поведения блокировки загрузчика DLL.
Независимо от того,
_beginthread{ex}
выполняет ли какое-либо специальное управление памятью потоков / волокон во время выполнения C, как обсуждают другие ответы, оно реализовано (при условии динамического связывания со средой выполнения C) DLL, процессы, возможно, еще не загружены.Это не безопасно звонить
_beginthread*
изDllMain
. Я проверил это, написав DLL, загруженную с помощью функции Windows «AppInit_DLLs». Вызов_beginthreadex (...)
вместоCreateThread (...)
приводит к тому, что МНОГО важных частей Windows перестает работать во время загрузки, посколькуDllMain
точка входа блокируется в ожидании снятия блокировки загрузчика для выполнения определенных задач инициализации.Кстати, именно поэтому kernel32.dll имеет много перекрывающихся строковых функций, которые выполняет также среда выполнения C - используйте их,
DllMain
чтобы избежать подобных ситуаций.источник
Если вы читали книгу «Отладка приложений Windows» от Джеффри Рихтера, в ней он объясняет, что почти во всех случаях вы должны вызывать,
_beginthreadex
а не вызыватьCreateThread
._beginthread
это просто упрощенная оболочка_beginthreadex
._beginthreadex
инициализирует определенные внутренние компоненты CRT (C RunTime), которыеCreateThread
API не выполняет.Последствие использования
CreateThread
API вместо использования_begingthreadex
вызовов функций CRT может привести к неожиданным проблемам.Ознакомьтесь с этим старым журналом Microsoft Journal от Рихтера.
источник
Между ними больше нет разницы.
Все комментарии об утечках памяти и т. Д. Основаны на очень старых версиях <VS2005. Я провел несколько стресс-тестов много лет назад и смог развенчать этот миф. Даже Microsoft смешивает стили в своих примерах, почти никогда не используя _beginthread.
источник