я бы использовал _beginthreadex.
Со слипами я бы разобрался. Может не нады они? Регулировать переключение слипами не стал бы. Не угадаешь. Если уж надо чего-то ждать - используйте события.
а чем _beginthreadex реально лучше? вроде же это обертка над...03.05.06 16:34 Автор: makeworld Статус: Member
> я бы использовал _beginthreadex. > Со слипами я бы разобрался. Может не нады они? Регулировать > переключение слипами не стал бы. Не угадаешь. Если уж надо > чего-то ждать - используйте события.
а чем _beginthreadex реально лучше? вроде же это обертка над API функцией CreateThread
про синхронизацию это само собой
я просто не знал о том, что потоки завершаются автоматом при завершении главного потока
Это не ко мне. Это к Рихтеру.04.05.06 05:24 Автор: void <Grebnev Valery> Статус: Elderman
> я просто не знал о том, что потоки завершаются автоматом > при завершении главного потока
К винде это не имеет никакого отношения. Просто в C программа завершается при выходе из функции main. При его разработке никто не закладывался на многопоточность. Вот и приходится при выходе из main прибивать все "лишние" потоки. Если ты поставишь в настройках линкера точку входа, отличную от xxxCRTStartup (вместо xxx - всякие main, wmain, WinMain и wWinMain), то процесс у тебя не завершится (естественно большинством рантаймовых функций ты пользоваться не сможешь и аргументы argv/argc не получшь)
> Хэндл главного потока ей по крайней мере при создании > процесса известен, могла бы и запомнить, после чего > обработать так же, как рантайм.
Не вводи сущностей сверх необходимости и прочее.
А вообще красивый и управляемый код чаще всего имеет высокую степень обобщенности и симметрии. В том смысле, что если нет ОБЯЗАТЕЛЬНЫХ причин выделять какой либо один поток, то лучше не делать этого из эстетических соображений.
А рантайм занимается этим насколько я понимаю именно из за того, что стандарт C напрямую указывает завершать программу (независимо от того, в каком виде она представлена) при выходе из main. Насколько я помню в posix-е и потоков то нету. Один процесс - один поток исполнения (другое дело, что они могут разделять память, хендлы и пр.., но у каждого свой PID и такое прочее).
эстетика дело такое03.05.06 21:41 Автор: dl <Dmitry Leonov>
> К винде это не имеет никакого отношения. Просто в C > программа завершается при выходе из функции main. При его > разработке никто не закладывался на многопоточность. Вот и > приходится при выходе из main прибивать все "лишние" > потоки. Если ты поставишь в настройках линкера точку входа, > отличную от xxxCRTStartup (вместо xxx - всякие main, wmain, > WinMain и wWinMain), то процесс у тебя не завершится > (естественно большинством рантаймовых функций ты > пользоваться не сможешь и аргументы argv/argc не получшь) > > dl уже даже протестил: > http://bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m= > 134498
пост читал
теперь понятно, что дело в CRT, хотя в принципе, если создавать обычное приложение без изменения точки входа, откючения CRT и т.д., не важно на уровне CRT или на уровне ОС происходит принудительное завершение потоков, результат один и тот же.
> пост читал > теперь понятно, что дело в CRT, хотя в принципе, если > создавать обычное приложение без изменения точки входа, > откючения CRT и т.д., не важно на уровне CRT или на уровне > ОС происходит принудительное завершение потоков, результат > один и тот же. как сказать
#include "windows.h"
DWORD CALLBACK trd(void *)
{
for(;;)Sleep(1000);
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
CreateThread(NULL,0,trd,NULL,0,NULL);
ExitThread(0);
return 0;
}
[UPD]
BTW у меня есть сильное подозрение что когда у процесса заканчиваюцца потоки умирает он тоже не по собственному желанию а по приказу csrss.exe
Нет. Процесс убивается в ядре03.05.06 17:59 Автор: amirul <Serge> Статус: The Elderman
> BTW у меня есть сильное подозрение что когда у процесса > заканчиваюцца потоки умирает он тоже не по собственному > желанию а по приказу csrss.exe
DECLSPEC_NORETURN
VOID
PspExitThread(
IN NTSTATUS ExitStatus
)
{
// [skipped]
Thread = PsGetCurrentThread();
Process = THREAD_TO_PROCESS(Thread);
// [skipped]
if ( (Process->ThreadListHead.Flink == Process->ThreadListHead.Blink)
&& (Process->ThreadListHead.Flink == &Thread->ThreadListEntry) ) {
LastThread = TRUE;
if ( ExitStatus == STATUS_THREAD_IS_TERMINATING ) {
if ( Process->ExitStatus == STATUS_PENDING ) {
Process->ExitStatus = Process->LastThreadExitStatus;
}
} else {
Process->ExitStatus = ExitStatus;
}
DbgkExitProcess(ExitStatus);
}
// [skipped]
if ( LastThread && Process->Win32Process ) {
(PspW32ProcessCallout)(Process,FALSE); // Вот тут он разрегистрируется в csrss-е
}
// [skipped]
//
// If this is the last thread in the process, then clean the address space
//
if ( LastThread ) {
if (!(ExChangeHandle(PspCidTable,Process->UniqueProcessId, PspMarkCidInvalid, PSP_INVALID_ID))) {
KeBugCheck(CID_HANDLE_DELETION);
}
KeQuerySystemTime(&Process->ExitTime);
PspExitProcess(TRUE,Process);
}
// [skipped]
}
---
Такие дела.
Да, все функции убивания потока заканчиваются в этой самой PspExitThread. Если TerminateThread вызван для текущего потока, то напрямую, а если для другого - через special APC
ну я имел ввиду относительно моего примера03.05.06 17:49 Автор: makeworld Статус: Member Отредактировано 03.05.06 17:53 Количество правок: 4
> #include "windows.h" > > DWORD CALLBACK trd(void *) > { > for(;;)Sleep(1000); > } > int WINAPI WinMain( > HINSTANCE hInstance, // handle to current instance > HINSTANCE hPrevInstance, // handle to previous instance > LPSTR lpCmdLine, // command line > int nCmdShow // show state > ) > { > CreateThread(NULL,0,trd,NULL,0,NULL); > ExitThread(0); > return 0; > }
ну я имел ввиду относительно моего примера. А так вообще конечно надежней было бы, если бы этим ОС занималась. Тут вообще конфликт получается. С одной стороны есть CRT, а с другой вполне легальная функция ExitThread(), которой до CRT и ее функций, вызываюшихся после выхода из main/WinMain и т.д., дела нет.
именно тем что это обертка над...03.05.06 16:54 Автор: Killer{R} <Dmitry> Статус: Elderman
Она дает знать CRT о том что тред запускается/завершается. Если ты не юзаешь CRT'шные функции в треде (что маловероятно), то можно и CreateThread заюзать.
т.е. CRT-шные функции, используемые в потоке, будут работать...03.05.06 17:26 Автор: makeworld Статус: Member
Точнее, для глобальных данных, используемых этими функциями, будет сделана обертка, привязанная к конкретному потоку, так чтобы их совместное использование из разных потоков не привело к глюкам.
Хотя на самом деле все не так страшно и может даже проскочить:
"Ой, вместо _beginthreadex я по ошибке вызвал CreateThread
Вас, наверное, интересует, что случится, если создать поток не библиотечной функ цией _begintbreadex, а Windows-функцией CreateThread Когда этот поток вызовет какую-нибудь библиотечную функцию, которая манипулирует со структурой tiddata, произойдет следующее. (Большинство библиотечных функций реентерабсльно и не требует этой структуры ) Сначала эта функция попытается выяснить адрес блока дан ных потока (вызовом TleGetValue). Получив NULL вместо адреса tiddata, она узнает, что вызывающий поток не сопоставлен с таким блоком. Тогда библиотечная функция тут
же создаст и инициализирует блок tiddata для вызывающего потока. Далее этот блок будет сопоставлен с потоком (через TlsSetValue) и останется при нем до тех пор, пока выполнение потока нс прекратится, С этого моменга данная функция (как, впрочем, и любая другая из библиотеки С/С++) сможет пользоваться блоком tiddata потока.
Как это ни фантасгично, но Ваш поток будет работать почти без глюков. Хотя некоторые проблемы все же появятся. Во-первых, если этот поток воспользуется биб лиотечной функцией signal, весь процесс завершится, так как SEH-фрейм не подго товлен. Во-вторых, если поток завершится, не вызвав endtbreadex, его блокданных не высвободится и произойдет утечка памяти. (Да и кто, интересно, вызовет end threadex иэ потока, созданного с помощью CreateTbread?)".
ясно, спасибо.03.05.06 20:03 Автор: makeworld Статус: Member
так вот если в документации написано чтотоНАДОделать так, а на практике известно что в принципе работает и по другому писать надо все равно именноТАКкак написано. Тк имплементация данной функции может поменяться как угодно любым хотфиксом, функция будет работать так как написано в документации, но не так как работала в прошлой версии CRT. В результате - юзера ругают программистов, пишут в техсуппорт, техсуппорт отправляет это дело манагерам, манагеры - ковыряют кто написал код который только делает вид что работает и увольняют его. Вот это основная причина почему надо юзать _beginthreadex вместо CreateThread, а не особенность поведения signal в внештатной ситуации в конкретной имплементации CRT.
Есть такое слово03.05.06 17:31 Автор: Killer{R} <Dmitry> Статус: Elderman Отредактировано 03.05.06 17:33 Количество правок: 1
надо
Что и как там работает - тебя вообще в данном случае не должно интересовать, и если в конкретной версии CRT и твоих исходников CreateThread работает нормально это не значит что всегда так будет.
> надо > Что и как там работает - тебя вообще в данном случае не > должно интересовать, и если в конкретной версии CRT и твоих > исходников CreateThread работает нормально это не значит > что всегда так будет.
Кстати, в VC 2005 нет single-threaded libraries, есть только multi-threaded, и по дефолту для Debug-сборки стоит Multi-threaded Debug DLL, а для Release - Multi-threaded DLL. Т.е. главные довод, приведенный в линке, отбрасывается.
Хотя в принципе, ради избежания гемора с CRT функциями в потоках в будущем, лучше наверное использовать _beginthreadex.