Библиотечные функции, которые лучше не вызывать
В библиотеке С/С++ содержится две функции:
unsigned long _beginthread( void (__cdecl *stait_address)(void *), unsigned stack_size, void *arglist);
и
void _endthread(void);
Первоначально они были созданы для того, чем теперь занимаются новые функции _beginthreadex и _endthreadex. Нo, как видите, у _begintbread параметров меньше, и, следовательно, ее возможности ограничены в сравнении с полнофункциональной beginthreadex. Например, работая с _beginthread, нельзя создать поток с атрибутами защиты, отличными от присваиваемых по умолчанию, нельзя создать поток и тут же его задержать — нельзя даже получить идентификатор потока. С функцией _endthread та же история; она не принимает никаких параметров, а это значит, что по окончании работы потока его код завершения всегда равен 0.
Однако с функцией _endthread дело обстоит куда хуже, чем кажется: перед вызовом ExitThread она обращается к CloseHandle и передает ей описатель нового потока. Чтобы разобраться, в чем тут проблема, взгляните на следующий код:
DWORD dwExitCode;
HANDLE hThreatf = _beglntnread(...);
GetExitCodeThread(hThread &dwExitCode);
CloseHandle(hThread);
Весьма вероятно, что созданный поток отработает и завершится еще до того, как первый поток успеет вызвать функцию GetExitCodeThread. Если так и случится, значение в hThread окажется недействительным, потому что _endtbread уже закрыла описатель нового потока. И, естественно, вызов CloseHandle дает ошибку.
Новая функция _endthreadex, не закрывает описатель потока, поэтому фрагмент кода, приведенный выше, будет нормально работать (если мы, конечно, заменим вызов _beginthread на вызов _beginthreadex). И в заключение, напомню еще раз: как только функция потока возвращает управление, _beginthreadex самостоятельно вызывает _endthreadex, a begtnthread обращается к _endthread.