Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > как корректно остановить поток?


Автор: andrew_121 14.5.2009, 14:51
Подскажите, как правильно завершить оного?

Автор: GoldFinch 14.5.2009, 15:07
TerminateThread()
что значит корректно? все данные в стеке потока убьются, данные в TLS убьются, данные в хипе останутся, данные в секции данных тоже останутся, впрочем обо всем этом написано в msdn

напиши откуда ты собрался его завершать.
если извне - только TerminateThread()
если из самого потока, то либо return в функции потока, либо ExitThread в любом месте

алсо, остановить или завершить?

Автор: andrew_121 14.5.2009, 15:15
Цитата(GoldFinch @  14.5.2009,  15:07 Найти цитируемый пост)
если извне - только TerminateThread()

Да. Извне.

Цитата(GoldFinch @  14.5.2009,  15:07 Найти цитируемый пост)
алсо, остановить или завершить?

Завершить.

Автор: Lazin 14.5.2009, 15:26
не стоит использовать CreateThread, вместо этого нужно использовать beginthread beginthreadex, так как они инициализируют структуры данных в TLS, которые необходимы стандартной библиотеке, CreateThread этого не делает...

Цитата(GoldFinch @  14.5.2009,  15:07 Найти цитируемый пост)
TerminateThread()

использовать нельзя, после вызова этой ф-ии твое приложение может некорректно работать
Цитата(MSDN)

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:


  • If the target thread owns a critical section, the critical section will not be released. 
  • If the target thread is allocating memory from the heap, the heap lock will not be released. 
  • If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. 
  • If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL. 


Цитата(GoldFinch @  14.5.2009,  15:07 Найти цитируемый пост)
ExitThread 

то-же не стОит
Цитата(MSDN)

ExitThread is the preferred method of exiting a thread in C code. However, in C++ code, the thread is exited before any destructors can be called or any other automatic cleanup can be performed. Therefore, in C++ code, you should return from your thread function.
если конечно ты не пишешь на Си
что-бы корректно завершить поток, нужно сообщить ф-ии потока, что пора завершаться, к примеру
Код

volatile bool run = true;
...
void thread_fn()
{
    while(run)
    {
        ....
    }
}
...
void stop_thread() 
{
    run = false;
    WaitForSingleObject(hThread, INFINITE);//нужно не забывать обрабатывать ошибки
}

либо можно использовать сообщения windows
Код

void thread_fn()
{
    MSG msg;
    while(GetMessage(&msg, 0, 0))
    {
        if (msg.message == WM_QUIT) return;
        ....
    }
}
...
void stop_thread()
{
    PostThreadMessage(hThread, WM_QUIT, 0, 0);//нужно не забывать обрабатывать ошибки
    WaitForSingleObject(hThread, INFINITE);//нужно не забывать обрабатывать ошибки
}

Автор: GoldFinch 14.5.2009, 15:41
Lazin, если приложение некорректно работает после TerminateThread() это недочет программиста, а не проблемы api функции

есть еще такой вариант завершения:

Код

void ThreadFunc(void*) {
    ....
    ThreadCleanup();
   //!!!! сюда управлеине передано не будет
}
void ThreadCleanup() {
   //код освобождения памяти и ресурсов
   ExitThread();
}

//переводим поток на код завершения
CONTEXT ctx;
GetThreadContext(hThr,&ctx);
ctx.eip=&ThreadCleanup;
SetThreadContext(hThr,&ctx);

однако это не избавит от "If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent"
но такие вобщем-то редкие случаи можно обрабатывать отдельно, флаги выставлять например

Добавлено через 2 минуты и 37 секунд
еще можно хранить все выделенные потоком ресурсы\память в глобальном объекте, и убивать их после TerminateThread()

Автор: Lazin 14.5.2009, 15:47
Цитата(GoldFinch @  14.5.2009,  15:41 Найти цитируемый пост)
если приложение некорректно работает после TerminateThread() это недочет программиста, а не проблемы api функции

это проблемы программиста, который вызывает такие функции

Автор: mrbrooks 14.5.2009, 15:59
GoldFinch  С Lazin'ым согласится старик Рихтер.
andrew_121, собственно он же рекомендует использовать beginthreadex вместо CreateThread 

Автор: Alca 14.5.2009, 16:07
GoldFinch, слушай что профи говорит (Lazin) smile

Добавлено @ 16:08
Можно еще ивенты заюзать. 

Автор: SenkraD 14.5.2009, 17:26
andrew_121, собстевнно я согласен с Lazin, Alca

Автор: azesmcar 14.5.2009, 17:33
andrew_121

забудь про TerminateThread. Поток нужно завершать изнутри, а как сказать своему потоку что он должен завершится смотри пост Lazin. В принципе подойдет любой механизм обмена сообщениями между потоками.
Цитата(GoldFinch @  14.5.2009,  15:07 Найти цитируемый пост)
TerminateThread()

а еще
exit(0) и TerminateProcess вместо return 0;
нахрена вообще придумали нормальное завершение процессов и потоков..всех поубивать

Автор: GoldFinch 14.5.2009, 18:19
all
вы решаете только те задачи которые придумываете сами?
если есть задача убить поток извне - значит ее надо решать, а не говорить "Поток нужно завершать изнутри"
задача ТС звучит "Поток нужно завершать ИЗВНЕ"
почему именно извне? если вы не можете придумать такую ситуацию, это не говорит что таких ситуаций нет

Автор: azesmcar 14.5.2009, 19:09
Цитата(GoldFinch @  14.5.2009,  18:19 Найти цитируемый пост)
вы решаете только те задачи которые придумываете сами?

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

Цитата(GoldFinch @  14.5.2009,  18:19 Найти цитируемый пост)
если есть задача убить поток извне - значит ее надо решать, а не говорить "Поток нужно завершать изнутри"

замечательно...где в вопросе сказано что поток надо убить?

Цитата(andrew_121 @  14.5.2009,  14:51 Найти цитируемый пост)
Подскажите, как правильно завершить оного? 

если ты считаешь что правильным завершением потока является убийство - это твое право.


Цитата(GoldFinch @  14.5.2009,  18:19 Найти цитируемый пост)
почему именно извне? если вы не можете придумать такую ситуацию, это не говорит что таких ситуаций нет 

не творческие мы личности..что поделать

Автор: jonie 15.5.2009, 10:55
Цитата


если есть задача убить поток извне - значит ее надо решать, а не говорить "Поток нужно завершать изнутри"
задача ТС звучит "Поток нужно завершать ИЗВНЕ"
что первее курица или яйцо ?)

Завершать потоки убийством крайне плохая идея. У нас есть сервис с ватч догом на работе, один поток котролирует другие (около 150 потоков крутится). Если поток не отвечает своевременно то, его убивают. Итогом этого служит что сервис может работать месяцами, но в определенный момент (после треминайт трейд) начинается коллапс, и все потоки начинают сыпаться.... 

Автор: Rickert 15.5.2009, 11:08
А если в потоке стоит получение данных через блокирующий сокет? То бишь аля:
Код
while(r != (-1)) {r = recv(...);...}

Тогда что предлогается? Засунуть цикл в другой цикл, который будет ловить сообщения для потока? А если собщение придёт(а так скорее всего и будет), в момент когда будет вызвана блок. функция recv() ?
CloseHandle - почему не подойдёт?
ИМХО: способов много, но надо применять каждому для своей ситуации и нету "правильного" способа, как нет "правильного" синглтона.

Автор: mrbrooks 15.5.2009, 11:16
 smile 
jonie, Rickert - почему вы не сказали что Lazin прав?

Цитата(Rickert @  15.5.2009,  11:08 Найти цитируемый пост)
CloseHandle - почему не подойдёт?

а это что - завершит поток?  smile 


Автор: Lazin 15.5.2009, 11:24
Цитата(Rickert @  15.5.2009,  11:08 Найти цитируемый пост)
А если в потоке стоит получение данных через блокирующий сокет?

то нужно использовать неблокирующий сокет smile 

Автор: Lazin 15.5.2009, 18:45
Цитата(jonie @  15.5.2009,  10:55 Найти цитируемый пост)
Завершать потоки убийством крайне плохая идея. У нас есть сервис с ватч догом на работе, один поток котролирует другие (около 150 потоков крутится). Если поток не отвечает своевременно то, его убивают. Итогом этого служит что сервис может работать месяцами, но в определенный момент (после треминайт трейд) начинается коллапс, и все потоки начинают сыпаться....

В таких случаях можно вынести часть потоков в один, или несколько дочерних процессов, и обмениваться с ним(и) информацией через какой-нибудь механизм IPC. В случае, если не отвечает - прибить. Разделяй и властвуй smile 

Автор: Rickert 15.5.2009, 18:54
Lazin, и всё время крутить цикл, а потом ещё добавить мудрый sleep() ?
Цитата(mrbrooks @  15.5.2009,  11:16 Найти цитируемый пост)
jonie, Rickert - почему вы не сказали что Lazin прав?

А должен был? smile 
Цитата(mrbrooks @  15.5.2009,  11:16 Найти цитируемый пост)
а это что - завершит поток?

А что - нет?

Автор: Lazin 15.5.2009, 18:58
Цитата(Rickert @  15.5.2009,  18:54 Найти цитируемый пост)
А должен был?

combo breaker
Цитата(Rickert @  15.5.2009,  18:54 Найти цитируемый пост)
А что - нет? 

нет smile

Добавлено через 1 минуту и 36 секунд
Цитата(Rickert @  15.5.2009,  18:54 Найти цитируемый пост)
и всё время крутить цикл, а потом ещё добавить мудрый sleep() ?

если коротко, то нет.. вместо этого использовать порты завершения или сообщения windows для организации асинхронной работы

Автор: GoldFinch 15.5.2009, 19:00
Цитата(Lazin @  15.5.2009,  19:58 Найти цитируемый пост)
нет smile  

проверял?
Цитата(Lazin @  15.5.2009,  12:24 Найти цитируемый пост)
то нужно использовать неблокирующий сокет 

а если сторонняя библиотека?

Автор: Lazin 15.5.2009, 19:00
блокирующий сокет разве не может прерывать ожидание по таймауту, я какбэ не в курсе.

Добавлено через 3 минуты и 40 секунд
Цитата(GoldFinch @  15.5.2009,  19:00 Найти цитируемый пост)
проверял?

Цитата(MSDN)

The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.

Автор: andrew_121 15.5.2009, 19:07
Цитата(Lazin @  14.5.2009,  15:26 Найти цитируемый пост)
void stop_thread() {    run = false;    WaitForSingleObject(hThread, INFINITE);//нужно не забывать обрабатывать ошибки}

А CloseHandle() вызывать после, нужно?

Автор: GremlinProg 15.5.2009, 19:09
нужно

Добавлено через 1 минуту и 49 секунд
если не использовать _beginthread

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)