информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Портрет посетителяЗа кого нас держат?
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Ядро Linux избавляется от российских... 
 20 лет Ubuntu 
 Tailscale окончательно забанила... 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
эстетика дело такое 03.05.06 21:41  Число просмотров: 2998
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
зато не нужно было бы таскать из программы в программу один и тот же код :)
<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