Полная последовательная цепочка Начать... с правильными параметрами обработчиков, защитой повторного запуска и отдельным обработчиком ошибок.
Где и как запускать
Модуль пустой управляемой формы учебной внешней обработки; тонкий или толстый клиент Windows. Вставьте весь модуль. Это не серверный код.
Подготовка
Создайте учебную внешнюю обработку с пустой управляемой основной формой. Создайте команду УчебныйПример и кнопку этой команды.
В свойстве команды Действие выберите процедуру УчебныйПример. Вставьте полный приведённый модуль формы.
Откройте EPF в тонком или толстом клиенте Windows и нажмите кнопку. Не переносите Ждать и Асинх в серверный общий модуль.
Пример работает только со своими данными в памяти; записи в базу, файлы и сеть нет.
Эти методы проверяются по установленной справке 8.5.1.1343, но фактический запуск в 1С здесь не подтверждён.
&НаКлиенте
Перем ВыполняетсяУчебнаяЦепочка;
&НаКлиенте
Процедура УчебныйПример(Команда)
Если ВыполняетсяУчебнаяЦепочка = Истина Тогда
ВызватьИсключение "Дождитесь завершения собственной цепочки";
КонецЕсли;
Состояние = Новый Структура("Источник,Целевой,Буфер", Неопределено, Неопределено, Неопределено);
Попытка
Состояние.Источник = Новый ПотокВПамяти;
Состояние.Целевой = Новый ПотокВПамяти;
ИсходныйБуфер = Новый БуферДвоичныхДанных(5);
Для ИндексБайта = 0 По 4 Цикл
ИсходныйБуфер.Установить(ИндексБайта, (ИндексБайта + 1) * 10);
КонецЦикла;
ВыполняетсяУчебнаяЦепочка = Истина;
Состояние.Источник.НачатьЗапись(ОповещениеПотока("ПослеЗаписи", Состояние), ИсходныйБуфер, 1, 3);
Исключение
ВыполняетсяУчебнаяЦепочка = Ложь;
ОшибкаЗапуска = ОписаниеОшибки();
ОшибкиЗакрытия = ЗакрытьСобственныеПотоки(Состояние.Источник, Состояние.Целевой);
ВызватьИсключение ОшибкаЗапуска + " " + ОшибкиЗакрытия;
КонецПопытки;
КонецПроцедуры
&НаКлиенте
Функция ОповещениеПотока(ИмяОбработчика, Состояние)
Возврат Новый ОписаниеОповещения(ИмяОбработчика, ЭтаФорма, Состояние, "ОшибкаУчебнойЦепочки", ЭтаФорма);
КонецФункции
&НаКлиенте
Процедура ОшибкаУчебнойЦепочки(Ошибка, СтандартнаяОбработка, Состояние) Экспорт
ВыполняетсяУчебнаяЦепочка = Ложь;
ОшибкиЗакрытия = ЗакрытьСобственныеПотоки(Состояние.Источник, Состояние.Целевой);
Если Не ПустаяСтрока(ОшибкиЗакрытия) Тогда
Сообщить(ОшибкиЗакрытия);
КонецЕсли;
СтандартнаяОбработка = Истина;
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗаписи(Состояние) Экспорт
Состояние.Источник.НачатьПереход(ОповещениеПотока("ПослеПереходаИсточника", Состояние), 0, ПозицияВПотоке.Начало);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПереходаИсточника(Позиция, Состояние) Экспорт
Сообщить(Позиция = 0);
Состояние.Источник.НачатьКопированиеВ(ОповещениеПотока("ПослеКопирования", Состояние), Состояние.Целевой, 2);
КонецПроцедуры
&НаКлиенте
Процедура ПослеКопирования(Скопировано, Состояние) Экспорт
Сообщить(Скопировано = 2);
Состояние.Целевой.НачатьПолучениеРазмера(ОповещениеПотока("ПослеРазмера", Состояние));
КонецПроцедуры
&НаКлиенте
Процедура ПослеРазмера(Размер, Состояние) Экспорт
Сообщить(Размер = 2);
Состояние.Целевой.НачатьУстановкуРазмера(ОповещениеПотока("ПослеУсечения", Состояние), 1);
КонецПроцедуры
&НаКлиенте
Процедура ПослеУсечения(Состояние) Экспорт
Состояние.Целевой.НачатьСбросБуферов(ОповещениеПотока("ПослеСброса", Состояние));
КонецПроцедуры
&НаКлиенте
Процедура ПослеСброса(Состояние) Экспорт
Состояние.Целевой.НачатьПереход(ОповещениеПотока("ПослеПереходаПриемника", Состояние), 0, ПозицияВПотоке.Начало);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПереходаПриемника(Позиция, Состояние) Экспорт
Сообщить(Позиция = 0);
Состояние.Буфер = Новый БуферДвоичныхДанных(5);
Для ИндексБайта = 0 По 4 Цикл
Состояние.Буфер.Установить(ИндексБайта, 9);
КонецЦикла;
Состояние.Целевой.НачатьЧтение(ОповещениеПотока("ПослеЧтения", Состояние), Состояние.Буфер, 2, 3);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЧтения(Прочитано, Состояние) Экспорт
Сообщить(Прочитано = 1);
Сообщить(Состояние.Буфер.Получить(2) = 20);
Сообщить(Состояние.Буфер.Получить(3) = 9);
Состояние.Целевой.НачатьЗакрытие(ОповещениеПотока("ПослеЗакрытияПриемника", Состояние));
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияПриемника(Состояние) Экспорт
Состояние.Целевой = Неопределено;
Состояние.Источник.НачатьЗакрытие(ОповещениеПотока("ПослеЗакрытияИсточника", Состояние));
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияИсточника(Состояние) Экспорт
Состояние.Источник = Неопределено;
ВыполняетсяУчебнаяЦепочка = Ложь;
Сообщить("Собственная цепочка завершена, оба потока закрыты");
КонецПроцедуры
&НаКлиенте
Функция ЗакрытьСобственныеПотоки(Первый, Второй)
Ошибки = "";
Если Первый <> Неопределено Тогда
Попытка
Первый.Закрыть();
Исключение
Ошибки = "Первый поток не закрыт: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
Если Второй <> Неопределено Тогда
Попытка
Второй.Закрыть();
Исключение
Ошибки = Ошибки + " Второй поток не закрыт: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
Возврат Ошибки;
КонецФункцииРазбор по шагам
Каждый следующий этап начинается только из экспортного обработчика предыдущего, не сразу после НачатьЗапись.
После записи, установки размера, сброса буферов и закрытия обработчик получает только Состояние. После перехода — Позиция и Состояние, после копирования/чтения — фактическое количество и Состояние.
Источник содержит 20/30/40; приёмник после копирования 20/30, после сокращения 20. В чтении возвращается 1, а не запрошенные 3.
Все ОписаниеОповещения сохраняют ту же структуру ресурсов и назначают экспортный обработчик ошибки с тремя параметрами: Ошибка, СтандартнаяОбработка, Состояние.
При ошибке отдельно пытаемся закрыть оба потока, сообщаем ошибки освобождения и оставляем стандартную обработку первичной ошибки включённой.
При успешном асинхронном закрытии ссылка соответствующего потока очищается. Сообщение о завершении появляется только из последнего обработчика после закрытия источника.
Как проверить результат
Семь контрольных сравнений дают Истина, в конце сообщение о завершении собственной цепочки.
Повторный запуск во время выполнения запрещён; после завершения разрешён. Ошибки API не превращаются в успешное завершение.
Ожидаемый результат
Показаны все этапы настоящего конвейера оповещений и жизненный цикл собственных ресурсов.
На что обратить внимание
Экспорт и сигнатуры обработчиков обязательны; не добавляйте лишний аргумент Количество после записи или закрытия.
Структура передаётся как дополнительный параметр оповещения, не как объект результата чтения.
Не заменяйте ошибки освобождения пустым Исключение; не запускайте следующий этап до оповещения.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.