Задача следующая: один поток запускает другой поток и передает ему адрес своего экземпляра 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)
