информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Где водятся OGRыАтака на Internet
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
примерно так 03.05.06 19:43  Число просмотров: 3281
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
Точнее, для глобальных данных, используемых этими функциями, будет сделана обертка, привязанная к конкретному потоку, так чтобы их совместное использование из разных потоков не привело к глюкам.

Хотя на самом деле все не так страшно и может даже проскочить:

"Ой, вместо _beginthreadex я по ошибке вызвал CreateThread

Вас, наверное, интересует, что случится, если создать поток не библиотечной функ цией _begintbreadex, а Windows-функцией CreateThread Когда этот поток вызовет какую-нибудь библиотечную функцию, которая манипулирует со структурой tiddata, произойдет следующее. (Большинство библиотечных функций реентерабсльно и не требует этой структуры ) Сначала эта функция попытается выяснить адрес блока дан ных потока (вызовом TleGetValue). Получив NULL вместо адреса tiddata, она узнает, что вызывающий поток не сопоставлен с таким блоком. Тогда библиотечная функция тут

же создаст и инициализирует блок tiddata для вызывающего потока. Далее этот блок будет сопоставлен с потоком (через TlsSetValue) и останется при нем до тех пор, пока выполнение потока нс прекратится, С этого моменга данная функция (как, впрочем, и любая другая из библиотеки С/С++) сможет пользоваться блоком tiddata потока.

Как это ни фантасгично, но Ваш поток будет работать почти без глюков. Хотя некоторые проблемы все же появятся. Во-первых, если этот поток воспользуется биб лиотечной функцией signal, весь процесс завершится, так как SEH-фрейм не подго товлен. Во-вторых, если поток завершится, не вызвав endtbreadex, его блокданных не высвободится и произойдет утечка памяти. (Да и кто, интересно, вызовет end threadex иэ потока, созданного с помощью CreateTbread?)".
<programming>
[Win32] Не создается поток 30.04.06 14:58   [Killer{R}]
Автор: makeworld Статус: Member
<"чистая" ссылка>
есть такой код. CreateThread() отрабатывает нормально, но признаков работы потока нет. использую VC++ 2005. не могу понять, в чем дело..

#include <windows.h>
#include <stdio.h>

void func();
DWORD WINAPI ThreadProc(LPVOID lParam);

int main() {
	func();
	return 0;
}

void func() {
	unsigned int tid;
	char test[30]={0};
	
	memset(&test[0], 'A', 29);
	printf("%s\n", test);


	HANDLE hT1 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
	HANDLE hT2 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
	HANDLE hT3 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);

	if ((hT1 == INVALID_HANDLE_VALUE)|		(hT2 == INVALID_HANDLE_VALUE)|		(hT3 == INVALID_HANDLE_VALUE))
		printf("failed\n");

	int lastErr = GetLastError();
	if (lastErr)
		printf("last error = %d\n", lastErr);

}


DWORD WINAPI ThreadProc(LPVOID lParam) {
	char *p = (char *)lParam;

//	Sleep(100);

	printf("i'm thread %d\n", GetCurrentThreadId());
	printf("%s\n", p);

	MessageBox(NULL, TEXT("test"), TEXT("test"), MB_OK);

	return 0;
}

---
я бы использовал _beginthreadex. 03.05.06 05:09  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
я бы использовал _beginthreadex.
Со слипами я бы разобрался. Может не нады они? Регулировать переключение слипами не стал бы. Не угадаешь. Если уж надо чего-то ждать - используйте события.
а чем _beginthreadex реально лучше? вроде же это обертка над... 03.05.06 16:34  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> я бы использовал _beginthreadex.
> Со слипами я бы разобрался. Может не нады они? Регулировать
> переключение слипами не стал бы. Не угадаешь. Если уж надо
> чего-то ждать - используйте события.

а чем _beginthreadex реально лучше? вроде же это обертка над API функцией CreateThread

про синхронизацию это само собой

я просто не знал о том, что потоки завершаются автоматом при завершении главного потока
Это не ко мне. Это к Рихтеру. 04.05.06 05:24  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
В который раз замечаю, что меня не замечают (sic!) 03.05.06 17:24  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
- Доктор, меня игнорируют.
- Следующий

> я просто не знал о том, что потоки завершаются автоматом
> при завершении главного потока

К винде это не имеет никакого отношения. Просто в 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
а вообще этим могла бы заниматься и система 03.05.06 19:46  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
Хэндл главного потока ей по крайней мере при создании процесса известен, могла бы и запомнить, после чего обработать так же, как рантайм.
Могла бы, но незачем 03.05.06 21:15  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Хэндл главного потока ей по крайней мере при создании
> процесса известен, могла бы и запомнить, после чего
> обработать так же, как рантайм.

Не вводи сущностей сверх необходимости и прочее.
А вообще красивый и управляемый код чаще всего имеет высокую степень обобщенности и симметрии. В том смысле, что если нет ОБЯЗАТЕЛЬНЫХ причин выделять какой либо один поток, то лучше не делать этого из эстетических соображений.

А рантайм занимается этим насколько я понимаю именно из за того, что стандарт C напрямую указывает завершать программу (независимо от того, в каком виде она представлена) при выходе из main. Насколько я помню в posix-е и потоков то нету. Один процесс - один поток исполнения (другое дело, что они могут разделять память, хендлы и пр.., но у каждого свой PID и такое прочее).
эстетика дело такое 03.05.06 21:41  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
зато не нужно было бы таскать из программы в программу один и тот же код :)
пост читал 03.05.06 17:31  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> К винде это не имеет никакого отношения. Просто в 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 или на уровне ОС происходит принудительное завершение потоков, результат один и тот же.
[UPD]как сказать 03.05.06 17:36  
Автор: Killer{R} <Dmitry> Статус: Elderman
Отредактировано 03.05.06 17:46  Количество правок: 2
<"чистая" ссылка>
> пост читал
> теперь понятно, что дело в 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
<"чистая" ссылка>
> Она дает знать CRT о том что тред запускается/завершается.

т.е. CRT-шные функции, используемые в потоке, будут работать учитывая то, что выполняются внутри потока??

можно простой пример пользы от примения _beginthreadex
примерно так 03.05.06 19:43  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
Точнее, для глобальных данных, используемых этими функциями, будет сделана обертка, привязанная к конкретному потоку, так чтобы их совместное использование из разных потоков не привело к глюкам.

Хотя на самом деле все не так страшно и может даже проскочить:

"Ой, вместо _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
<"чистая" ссылка>
ясно, спасибо.

хотя signal не самая часто используемая функция, повод для использования именно CRT-обертки создания потока существенный
есть такие понятия как documentation и implementation 03.05.06 20:33  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
так вот если в документации написано чтотоНАДОделать так, а на практике известно что в принципе работает и по другому писать надо все равно именноТАКкак написано. Тк имплементация данной функции может поменяться как угодно любым хотфиксом, функция будет работать так как написано в документации, но не так как работала в прошлой версии CRT. В результате - юзера ругают программистов, пишут в техсуппорт, техсуппорт отправляет это дело манагерам, манагеры - ковыряют кто написал код который только делает вид что работает и увольняют его. Вот это основная причина почему надо юзать _beginthreadex вместо CreateThread, а не особенность поведения signal в внештатной ситуации в конкретной имплементации CRT.
Есть такое слово 03.05.06 17:31  
Автор: Killer{R} <Dmitry> Статус: Elderman
Отредактировано 03.05.06 17:33  Количество правок: 1
<"чистая" ссылка>
надо
Что и как там работает - тебя вообще в данном случае не должно интересовать, и если в конкретной версии CRT и твоих исходников CreateThread работает нормально это не значит что всегда так будет.

http://www.flounder.com/badprogram.htm
Кстати, в VC 2005 нет single-threaded libraries, есть только... 03.05.06 19:56  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> надо
> Что и как там работает - тебя вообще в данном случае не
> должно интересовать, и если в конкретной версии CRT и твоих
> исходников CreateThread работает нормально это не значит
> что всегда так будет.

Кстати, в VC 2005 нет single-threaded libraries, есть только multi-threaded, и по дефолту для Debug-сборки стоит Multi-threaded Debug DLL, а для Release - Multi-threaded DLL. Т.е. главные довод, приведенный в линке, отбрасывается.

Хотя в принципе, ради избежания гемора с CRT функциями в потоках в будущем, лучше наверное использовать _beginthreadex.

CreateThread in a C program
и будет тебе счастье :) 30.04.06 16:10  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
и будет тебе счастье :)

>
> int main() {
> func();
!!!!!!!!! Sleep(5000);
> return 0;
> }
>

правда счастье будет длиться 5 секунд :)
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach