Перейти к основному содержимому
Версия: 7.0

Оператор NEWTHREAD

Оператор NEWTHREAD - создание действия, которое выполняет другое действие в новом потоке.

Синтаксис

NEWTHREAD action
NEWTHREAD action SCHEDULE [PERIOD periodExpr] [DELAY delayExpr] [TO toPropertyId]
NEWTHREAD action CLIENT notificationPropertyId [TO toPropertyId]
NEWTHREAD action TO toPropertyId

Описание

Оператор NEWTHREAD создает действие, которое выполняет другое действие в новом потоке. Если оператор находится внутри NEWEXECUTOR, то поток берётся из созданной им службы выполнения (серверный пул либо клиентский диспетчер); иначе создаётся свободный поток на сервере приложений.

SCHEDULE запускает действие с задержкой и/или с периодическим повторением. Внутри NEWEXECUTOR ... CLIENT для отложенных и периодических запусков используется клиентский таймер, внутри NEWEXECUTOR ... THREADS — серверный планировщик пула. Без PERIOD действие выполняется один раз; с PERIOD — повторно, причём периодический поток не может быть присоединён к ожидающему NEWEXECUTOR ... WAIT, поскольку никогда не завершается.

CLIENT регистрирует действие как клиентское уведомление и записывает его идентификатор в notificationPropertyId. Сама по себе эта форма не отправляет уведомление ни на одно соединение — отправка остаётся за вызывающим кодом, который использует записанный идентификатор для целевой доставки. Окружающий NEWEXECUTOR ... WAIT не дожидается такого CLIENT p без TO — futures на это уведомление не регистрируется. Если же используется CLIENT p TO q, поток ожидается до фактического срабатывания уведомления (когда вызывающий код доставит идентификатор) либо до его удаления по тайм-ауту удержания. Для автоматической доставки действия на стороне клиента используется обычный NEWTHREAD action внутри NEWEXECUTOR ... CLIENT conn, без клаузы CLIENT.

TO сохраняет значение, возвращённое внутренним действием через RETURN, в указанное свойство. Внутреннее действие должно объявлять возвращаемое значение (через RETURN) и быть записано в блочной форме — NEWTHREAD { ... RETURN ...; } TO p или с обёрткой вроде NEWTHREAD NEWSESSION { ... RETURN ...; } TO p. Прямой вызов NEWTHREAD a(args) TO p грамматически разбирается как EXEC a(args) TO p внутреннего действия и не относится к данной форме NEWTHREAD ... TO. Форма допустима только внутри NEWEXECUTOR ... WAIT: запись выполняется по окончании потока, после чего сохранённые значения применяются в текущей сессии при выходе из NEWEXECUTOR. Сочетание PERIOD и TO запрещено, так как периодический поток не завершается.

Сессия изменений, в которой исполняется тело потока, зависит от места его исполнения, и это принципиальное различие между двумя режимами.

  • При серверной диспетчеризации (свободный поток либо NEWEXECUTOR ... THREADS) тело потока выполняется в той же сессии, что и вызывающий код. Сессии изменений не являются потокобезопасными — одновременная работа нескольких потоков с общими данными такой сессии приводит к гонкам, поэтому тело потока типично оборачивают в NEWSESSION.
  • При клиентской диспетчеризации (NEWEXECUTOR ... CLIENT, а также фактическое срабатывание уведомления, зарегистрированного через CLIENT p) тело потока выполняется на сервере приложений, но не в сессии вызывающего кода, а в собственной свежей сессии изменений на уровне навигатора клиентского соединения; эта сессия не привязана к какой-либо открытой форме. Действие может использовать интерактивные операторы (MESSAGE, открыть форму и т.п.) — они направляются в UI этого соединения; открытая таким действием форма получает свою собственную сессию по обычным правилам. Оборачивание в NEWSESSION не требуется.

Параметры

  • action

    Контекстно-зависимый оператор-действие, описывающий действие, которое будет выполнено в новом потоке.

  • periodExpr

    Выражение, значение которого определяет период повторения действия в миллисекундах. Тип значения — INTEGER или LONG, значение должно быть строго положительным.

  • delayExpr

    Выражение, значение которого определяет задержку перед первым запуском действия в миллисекундах. Тип значения — INTEGER или LONG, значение не должно быть отрицательным. По умолчанию (без DELAY) для однократного действия и для серверного периодического первый запуск происходит сразу; для клиентского периодического (NEWTHREAD ... SCHEDULE PERIOD ... внутри NEWEXECUTOR ... CLIENT) первый запуск без DELAY происходит через period, далее каждые period.

  • notificationPropertyId

    Идентификатор свойства класса INTEGER без параметров, в которое будет записан идентификатор зарегистрированного уведомления.

  • toPropertyId

    Идентификатор свойства, в которое записывается значение, возвращённое внутренним действием через RETURN. Арность свойства должна совпадать с арностью возвращаемого значения; если арность свойства на единицу больше и первый его параметр имеет тип INTEGER, в этот параметр записывается порядковый номер потока в окружающем NEWEXECUTOR.

Примеры

testNewThread () {
// Серверный пул потоков с ожиданием завершения и захватом результата
LOCAL r = INTEGER ();
NEWEXECUTOR {
NEWTHREAD { RETURN 42; } TO r;
} THREADS 1 WAIT;
MESSAGE 'r=' + r(); // r=42

// Однократное отложенное выполнение на сервере с захватом результата
LOCAL r2 = INTEGER ();
NEWEXECUTOR {
NEWTHREAD { RETURN 99; } SCHEDULE DELAY 2000 TO r2;
} THREADS 1 WAIT;
MESSAGE 'r2=' + r2(); // r2=99 примерно через 2 секунды

// Периодическое выполнение на стороне клиента
NEWEXECUTOR {
NEWTHREAD MESSAGE 'tick'; SCHEDULE PERIOD 10000 DELAY 5000;
} CLIENT currentConnection() NOWAIT;

// Регистрация клиентского уведомления, идентификатор которого сохраняется в notifId
LOCAL notifId = INTEGER ();
NEWTHREAD { MESSAGE 'on demand'; } CLIENT notifId;
// notifId() теперь хранит идентификатор зарегистрированного уведомления;
// вызывающий код может позже инициировать его доставку клиенту по этому идентификатору
}