Добавлено: 09 Август 2004, 16:57
Clarion 5.5D Enterprise
Задача следующая: один поток запускает другой поток и передает ему адрес своего экземпляра queue, которая должна быть заполнена в вызываемом потоке (типичное применение - выборка из файла по условию).
Сама очередь описана глобально с атрибутом thread.
Проблема: если в вызывающем потоке просто использовать ссылку на очередь и передать ее в вызываемый поток, то при возврате очередь не заполнена; а вот если сначала сделать new(queue), то все OK.
Где ошибка ???
Делать new не хочется, тем более, что и без него должно работать.
Привожу полный текст программы (можно сразу компилировать).
Bourkov Andrei bav@makler.ru
Написал: ClaList(2)
Задача следующая: один поток запускает другой поток и передает ему адрес своего экземпляра queue, которая должна быть заполнена в вызываемом потоке (типичное применение - выборка из файла по условию).
Сама очередь описана глобально с атрибутом thread.
Проблема: если в вызывающем потоке просто использовать ссылку на очередь и передать ее в вызываемый поток, то при возврате очередь не заполнена; а вот если сначала сделать new(queue), то все OK.
Где ошибка ???
Делать new не хочется, тем более, что и без него должно работать.
Привожу полный текст программы (можно сразу компилировать).
Код: Выделить всё
!==============================================================================================================
PROGRAM
MAP
StartFill ! Процедура запуска и показа рез-тов заполнения очереди Q
Fill(string) ! Заполнение выполняется здесь
.
App APPLICATION(' Main'),AT(0,0,250,257),SYSTEM,MAX,RESIZE
MENUBAR
ITEM('Начать'),USE(?Start)
END
END
Q queue,thread ! Очередь для заполнения
s string(10)
.
QRefsQueue queue ! Глобальная очередь, используемая всеми потоками для определения, с каким экземпляром Q работаем
Thrd short ! Номер потока, в котором показывается Q
QRef &Q ! Ссылка на Q в данном потоке
.
CODE
OPEN(App)
ACCEPT
CASE EVENT()
OF EVENT:CloseDown
break
OF EVENT:Accepted
case field()
of ?Start
stop('В App (thread=' & thread() & ') ' & address(Q)) ! Проверим адрес Q в основном потоке
t#=START(StartFill)
. . .
!----------------------------------------------------
StartFill procedure
Win WINDOW(' Кол-во записей в Q'),AT(0,0,104,201),FONT('MS Sans Serif',10,,,CHARSET:CYRILLIC),HVSCROLL, !
SYSTEM,GRAY,DOUBLE,MDI
BUTTON('Start'),AT(14,4,28,12),USE(?StartBtn),SKIP,FLAT
BUTTON('Stop'),AT(61,4,28,12),USE(?StopBtn),SKIP,FLAT,DISABLE
LIST,AT(4,20,96,174),USE(?List),VSCROLL,FONT('Courier New',10,,,CHARSET:CYRILLIC),COLOR(COLOR:Silver), !
FORMAT('20L(2)_~Заголовок~C@s20@E(,0C0C0C0H,,)') !,FROM(Q)
END
QR &Q
code
! QR &= Q !!! Так НЕ работает (т.е. в проц-ре Fill заполняется другой экземпляр Q),
! хотя показывает все время один и тот же адрес Q во все потоках.
! QR &= address(Q) !!! Так вообще выдает ошибку, хотя компилируется нормально и по документации должно работать
QR &= new(Q) !!! Так работает
OPEN(Win)
?List{PROP:From}=QR
ACCEPT
CASE EVENT()
OF EVENT:CloseDown
break
OF 500h ! Сообщение из Fill о занесении новой записи
Win{PROP:Text}='Кол-во записей: ' & records(QR) !(Q)
OF 501h ! Сообщение из Fill о завершении
disable(?StopBtn); enable(?StartBtn)
OF EVENT:Accepted
case field()
of ?StartBtn
stop('В StartCount (thread=' & thread() & ') ' & address(QR)) ! Проверим адрес экземпляра Q в этом потоке
QRefsQueue.Thrd=thread(); QRefsQueue.QRef &= QR
add(QRefsQueue,QRefsQueue.Thrd) ! Через эту запись передадим ссылку на экземпляр Q
newthread#=START(Fill,,thread())
enable(?StopBtn); disable(?StartBtn)
of ?StopBtn
POST(EVENT:CloseDown,,newthread#,1) ! Остановим заполнение Q
disable(?StopBtn); enable(?StartBtn)
.
. .
dispose(QR)
!----------------------------------------------------
! Эта процедура имитирует заполнение очереди записями из файла.
! Для ускорения процесса используется не событие от Timer, а
! повторная посылка в accept своего события 499h
Fill procedure(ParentThread)
HiddenWindow WINDOW(''),AT(0,-10,0,0),GRAY,MDI
END
QR &Q
cnt long, thread ! Счетчик шагов
code
QRefsQueue.Thrd=ParentThread
get(QRefsQueue,QRefsQueue.Thrd) ! Получим ссылку на Q, используемую в вызвавшем потоке
if errorcode()=0
QR &= QRefsQueue.QRef ! Нельзя напрямую использовать QRefsQueue.QRef, т.к. это глобальная переменная
else ! будет изменена при старте StartFill в др.потоке
stop('Не передан пар-р')
.
! здесь адрес должен быть таким же, как в вызвавшей StartFill
stop('В Count (thread=' & thread() & ') ' & address(QR))
cnt=0
open(HiddenWindow)
post(499h) ! Начнем цикл. Будет прерван по EVENT:CloseDown, пришедшему
accept ! от вызвавшего потока (StartFill) или после занесения в Q заданного кол-ва записей
case event()
of 499h
cnt +=1
if cnt %1000 =0
QR.s=all(chr(val('a')+cnt/1000-1), 10); add(QR)
post(500h,,ParentThread,1) ! Для показа в вызвавшем потоке процесса заполнения Q
.
! yield
if records(QR)>=50
break
else
post(499h) ! Следующий шаг (по Timer слишком медленно)
. .
.
close(HiddenWindow)
QRefsQueue.Thrd=ParentThread
get(QRefsQueue,QRefsQueue.Thrd) ! Вновь получим ссылку на Q, используемую в вызвавшем потоке
if errorcode()=0 ! и удалим ее за ненадобностью
delete(QRefsQueue)
.
post(501h,,ParentThread) ! Сообщим в StartFill, что заполнение завершено
Написал: ClaList(2)