Форум » [x]Harbour » Вопрос про потоки в harbour » Ответить

Вопрос про потоки в harbour

PSP: Что-то не нашел я способа, как можно прекратить выполнение потока, созданного hb_threadStart(). hb_threadJoin() не подходит, так как функция, выполняющаяся в потоке, никогда сама не завершится. Возможно ли такое в принципе? P.S. Вроде бы есть hb_threadQuitRequest(), но в исходниках для нее примечание: [quote]"this function call can be ignored by the destination thread in some cases. HVM does not guaranties that the QUIT signal will be always delivered."[/quote] Как быть? Известны ли эти самые "in some cases"?

Ответов - 14

Dima: Возможно это чем то поможет http://clipper.borda.ru/?1-4-0-00000359-000-30-0

PSP: Спасибо, Дима! Эту тему я читал раз пять. :) Видел, что в xHarbour есть StopThread(). А вот в Harbour аналога не нашел... Может плохо искал? Есть возможность остановить все потоки, но это не подходит. Нужно остановить один поток. Ткните носом, плиз, если такая возможность в Harbour есть. Спасибо.

Петр: PSP пишет: Видел, что в xHarbour есть StopThread(). А вот в Harbour аналога не нашел... Ну почему же, нашли - hb_threadQuitRequest() Известны ли эти самые "in some cases" Вот как пишет об этом автор реализации Przemyslaw Czerpak hb_threadQuitRequest() can be ignored by thread in some cases due to race condition. It may happen if thread will overwrite request send by caller simultaneously, f.e. by its own BREAK. I can resolve it but we can also leave it as is and document such behavior as expected or even remove this function. Killing other threads in such way is dangerous and can be used only for some simple situation. It's much safer when user uses his own mechanism to terminate treads in some safe for his code place


PSP: Спасибо, Петр! Скажите, а использование HB_THREAD_INHERIT_PUBLIC гарантирует, что функция, исполняющаяся в потоке, "увидит" изменения глобальных переменным? Я уже для себя этот метод испробывал. Вроде работает...

PSP: Сделал следующим образом: 1. Создал PUBLIC переменную - массив со списком запущенных потоков. 2. Сделал 2 функции: StartThread и StopThread для запуска и остановки потоков. 3. StartThread после успешного (проверяется) запуска потока добавляет в массив-список номер нового потока. 4. Если нужно поток убить, запускаем StopThread. Она удаляет из массива-списка нужный поток. 5. Функция, работающая в самом потоке, контроллирует наличие собственного номера потока (hb_threadSelf()) в массиве-списке. Если его там нет - завершает работу, поток закрывается. Может слехка топорно, но работает... :)

Andrey: PSP пишет: Сделал следующим образом: 1. Создал PUBLIC переменную - массив со списком запущенных потоков. 2. Сделал 2 функции: StartThread и StopThread для запуска и остановки потоков. 3. StartThread после успешного (проверяется) запуска потока добавляет в массив-список номер нового потока. 4. Если нужно поток убить, запускаем StopThread. Она удаляет из массива-списка нужный поток. 5. Функция, работающая в самом потоке, контроллирует наличие собственного номера потока (hb_threadSelf()) в массиве-списке. Если его там нет - завершает работу, поток закрывается. А можно исходники посмотреть ? Или пример самодостаточный..... Заранее спасибо...

PSP: Пример: [pre] #include "hbthread.ch" PROCEDURE Main() PUBLIC _aThreads := {} ? "Start..." StartThread( "threadShowDateTime", "@threadShowDateTime()" ) WAIT StopThread( "threadShowDateTime" ) CLS ? "Stop..." WAIT QUIT FUNCTION StartThread( cName, cFunc ) LOCAL i LOCAL pThId i := AScan( _aThreads, { | x | x[ 1 ] == cName } ) IF i == 0 .and. ! ISNIL( cFunc ) pThId := HB_ThreadStart( HB_THREAD_INHERIT_MEMVARS, &( cFunc ) ) IF hb_isPointer( pThId ) AAdd( _aThreads, { cName, pThId } ) END // IF END // IF RETURN NIL FUNCTION StopThread( cName ) LOCAL i i := AScan( _aThreads, { | x | x[ 1 ] == cName } ) IF i <> 0 ADel( _aThreads, i ) ASize( _aThreads, Len( _aThreads ) - 1 ) END // IF RETURN NIL FUNCTION threadShowDateTime() LOCAL cDate WHILE .T. IF ( AScan( _aThreads, { | x | x[ 2 ] == HB_ThreadSelf() } ) == 0 ) EXIT END // IF hb_DispOutAt( 1, 10, Date(), "G+/N" ) hb_DispOutAt( 1, 20, Time(), "R+/N" ) hb_releaseCPU() END // WHILE RETURN NIL [/pre]

Andrey: Спасибо большое !

PSP: Пожалуйста :)

Andrey: Что-то не собирается в Харборе. Я вообще-то не силен в нем.... Z:\hb30\bin\hbmk2.exe demo.hbp hbmk2: Compiling Harbour sources... Harbour 3.0.0 (Rev. 16951) Copyright (c) 1999-2011, http://harbour-project.org/ Compiling 'test.prg'... test.prg(6) Warning W0002 Ambiguous reference, assuming memvar '_ATHREADS' test.prg(30) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(35) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(47) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(50) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(51) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(51) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(64) Warning W0001 Ambiguous reference '_ATHREADS' test.prg(76) Warning W0003 Variable 'CDATE' declared but not used in function 'THREADSHOWDATETIME(60)' No code generated. hbmk2: Error: Running Harbour compiler (embedded). 1 (Z:\hb30\bin\harbour.exe) -n2 test.prg -w3 -es2 -o.hbmk\win\bcc\ -iZ:\BCC55\Include -iZ:\hb30\include -undef:.ARCH. -D__PLATFORM__WINDOWS -D__LITTLE_ENDIAN__ -D__ARCH32BIT__ Файл demo.hbp: -3rd=hbide_version=1.0 -3rd=hbide_title=Demo&HB_Tread -3rd=hbide_output=demo -inc -mt -w3 -es2 -gtwvg test.prg

PSP: Andrey пишет: Variable 'CDATE' declared but not used in function 'THREADSHOWDATETIME(60) Эту переменную можно убрать. Осталась от рабочего кода. Это ни на что не влияет. -w3 Слишком чувствительный уровень. Поэтому столько варнингов. По-умолчанию -w1 Возможно поэтому и Harbour.exe не запускается. Убери -w3 и -es2

Andrey: На другом теперь вылетает: Z:\hb30\bin\hbmk2.exe demo.hbp hbmk2: Linking... test.exe Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland Error: Unresolved external '_HB_FUN_ISNIL' referenced from Z:\HB30\HB_TREAD\.HBMK\WIN\BCC\TEST.OBJ hbmk2: Error: Running linker. 2 ilink32.exe @C:\DOCUME~1\86A9~1\LOCALS~1\Temp\tg9zfr.lnk

PSP: Добавь в начало #include "common.ch"

Andrey: PSP - Спасибо БОЛЬШОЕ ! Заработало.... Конечный текст для желающих test.prg #include "hbthread.ch" #include "common.ch" PROCEDURE Main() PUBLIC _aThreads := {} CLS ? "Start..." StartThread( "threadShowDateTime", "@threadShowDateTime()" ) ? WAIT StopThread( "threadShowDateTime" ) CLS ? "Stop..." ? WAIT QUIT FUNCTION StartThread( cName, cFunc ) LOCAL i LOCAL pThId i := AScan( _aThreads, { | x | x[ 1 ] == cName } ) IF i == 0 .and. ! ISNIL( cFunc ) pThId := HB_ThreadStart( HB_THREAD_INHERIT_MEMVARS, &( cFunc ) ) IF hb_isPointer( pThId ) AAdd( _aThreads, { cName, pThId } ) END // IF END // IF RETURN NIL FUNCTION StopThread( cName ) LOCAL i i := AScan( _aThreads, { | x | x[ 1 ] == cName } ) IF i <> 0 ADel( _aThreads, i ) ASize( _aThreads, Len( _aThreads ) - 1 ) END // IF RETURN NIL FUNCTION threadShowDateTime() LOCAL cDate WHILE .T. IF ( AScan( _aThreads, { | x | x[ 2 ] == HB_ThreadSelf() } ) == 0 ) EXIT END // IF hb_DispOutAt( 1, 10, Date(), "G+/N" ) hb_DispOutAt( 1, 20, Time(), "R+/N" ) hb_releaseCPU() END // WHILE RETURN NIL demo.hbp # # $Id$ # -3rd=hbide_version=1.0 -3rd=hbide_title=Demo&HB_Tread -3rd=hbide_output=demo -3rd=hbide_xhb=YES # -inc -mt -gtwin test.prg



полная версия страницы