Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

​ThreadStatic - уперся не пойму во что...

226  1 2 все
Murr патриот04.10.17 18:28
Murr
04.10.17 18:28 

ThreadStatic - уперся не пойму во что...


Написал тестовую многопоточку с шарингом ресурса внутри потока.

Т.е. все, кто работает внутри потока, получают доступ к одному и тому же экземпляру интересующего объекта.

Все класно.


Переношу все на рабочую систему.

Все тоже самое, только вокруг намотано еще много всякого.

Так не работает.

Уже упарился... топовому шаблону отдаю нужный стрингбилдер - он его помещает в треадстатик преременную и использует...

Вопрос - какого хрена второй шаблон не выполняемый в том же потоке не пользует тот же стринг билдер?

А хрен - простой как три рубля - стрингбилдер во втором шаблоне остается нуллом...


А в тестовом варианте все тоже самое, но все - тип-топ... блин... хммм

#1 
Программист коренной житель04.10.17 22:27
NEW 04.10.17 22:27 
в ответ Murr 04.10.17 18:28, Последний раз изменено 04.10.17 22:29 (Программист)

Может бать потому что ThreadStatic остается статиком только в пределах одного потока? А в другом потоке имеет другое значение?


A static field marked with T:System.ThreadStaticAttribute is not shared between threads. Each executing thread has a separate instance of the field, and independently sets and gets values for that field. If the field is accessed on a different thread, it will contain a different value.
#2 
Murr патриот04.10.17 23:04
Murr
NEW 04.10.17 23:04 
в ответ Программист 04.10.17 22:27

Ну так это и эксплуатируется - статик в пределах потока - сколько бы объектов не отрабатывало в пределах потока они все должны использовать один и тот же треадстатик объект. Другой поток есть другой поток - там свой объект.


На прототипе все так и работает. Все тоже самое в боевом варианте - не пашет...

#3 
AlexNek патриот04.10.17 23:06
AlexNek
04.10.17 23:06 
в ответ Murr 04.10.17 18:28
А в тестовом варианте все тоже самое, но все - тип-топ...

отложи проект в сторонку на некоторое время.

Потом сам найдешь ошибку. Что то добавил, изменил, пропустил. Бывает...


ThreadStatic - уперся не пойму во что...

А оно тебе надо? Описание никак не соответствует.

Лучше подобные вещи реализовывать самому.

И обязательно делать "длинный тест". А то часто бывает, полчаса/час работает без проблем, а целый день не выдерживает. В итоге происходят "непонятные" вылеты у заказчика.

#4 
Murr патриот04.10.17 23:28
Murr
NEW 04.10.17 23:28 
в ответ Murr 04.10.17 18:28

Вопрос - какого хрена второй шаблон не выполняемый в том же потоке не пользует тот же стринг билдер?

------

Опечатка. Читать как

Вопрос - какого хрена второй шаблон, выполняемый в том же потоке, не пользует тот же стрингбилдер? Он же один в потоке... так нет - берет с подстраховки нoвый...

#5 
Murr патриот04.10.17 23:35
Murr
04.10.17 23:35 
в ответ AlexNek 04.10.17 23:06

отложи проект в сторонку на некоторое время.

-----

Так уже... Это третий подход к снаряду...


А оно тебе надо?

------

Мне таки надо - уж больно вкусненько получается на многоядерниках в параллели - с 20 секунд до 0.9 сек...

Ну может быть надо самому объектиком манипулировать... подумаю...

Больше достает, что прототип - пашет, а рабочий вариант не идет...



И обязательно делать "длинный тест".

-----

Мне проще полностью перезапустить процесс.

#6 
AlexNek патриот04.10.17 23:55
AlexNek
04.10.17 23:55 
в ответ Murr 04.10.17 23:35
Так уже... Это третий подход к снаряду...

тогда ты сделал изменение которое считаешь правильным. Типа вместо интегер пользуем класс. Либо изменение прошло "автоматом" и ты его просто "не видишь".


Мне таки надо - уж больно вкусненько получается на многоядерниках в параллели - с 20 секунд до 0.9 сек...

имелся в виду ThreadStatic.

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


Мне проще полностью перезапустить процесс.

любишь приехать в воскресенье после обеда? бебе

#7 
Программист коренной житель05.10.17 09:10
NEW 05.10.17 09:10 
в ответ Murr 04.10.17 23:04
Все тоже самое в боевом варианте - не пашет...

Ну значит либо в боевом варианте доступ из другого потока, либо ты где-то обнуляешь созданный стрингбилдер.


Я бы исходил из того, что ThreadStatic работает правильно, а косяк где-то у тебя. Вообще статики - зло, а такие "полустатики" - двойное зло :)

#8 
Murr патриот05.10.17 09:48
Murr
NEW 05.10.17 09:48 
в ответ AlexNek 04.10.17 23:55

Либо изменение прошло "автоматом" и ты его просто "не видишь".

-----

Где-то цто-то Я не вижу. Это понятно.

Непонятно - что именно и где именно Я не вижу.

Проблема - много кода. Что мог - убрал с глаз долой, осталось - почти столько же сколько сколько в прототипе... все одно - не вижу...

Хотя... возможно виртуальность одного из методов мешает... посмотрю.


Как только поток можно реализовать как отдельный класс,

------

В моем случае - поток как метод в классе. Потому - должно работать.

Поменять - можно, но там появится куча проблем с передачей объекта суб-шаблонам.

Потому будет приятно не иметь дела передачей параметров вне начала выполнения метода.



любишь приехать в воскресенье после обеда?

------

Угу... особенно на другой конец шарика...

#9 
Murr патриот05.10.17 09:59
Murr
NEW 05.10.17 09:59 
в ответ Программист 05.10.17 09:10

Ну значит либо в боевом варианте доступ из другого потока,

-----

Другие потоки работают как другие потоки - в них те же самые проблемы.

Создание потоков - контролируется - есть класс Работник, есть класс Менеджер.

Менеджер создает Работников и управляет ими.

В частности - именно Менеджер определяет каким ресурсом будут пользоваться Работники.

Проблем с управлением не наблюдалось.


либо ты где-то обнуляешь созданный стрингбилдер.

------

Обнулять стрингбилдер - вообще плохая идея. Очень дорогой ресурс.

Когда Я тестил время создания и дропа стрингбилдера лет 6-7 назад, то выходило

чуть дольше файлового потока.

Так что стрингбилдеры хранятся в пуле, получаются и возвращаются туда Менеджером.

Во всем коде операции по созданию и обнулению стрингбилдеров есть только в пуле.


а косяк где-то у тебя.

-----

Ну так это понятно. Непонятно как отловить...



Вообще статики - зло

-----

Тебе показать код Оракла? Там статиков ой-ей... и падает при коннекте к 8-ке...

Все еще не доковырял где именно и как чинить...

#10 
Программист коренной житель05.10.17 10:37
05.10.17 10:37 
в ответ Murr 05.10.17 09:59
Ну так это понятно. Непонятно как отловить...

Ну можно сделать прорети и обеспечить доступ к переменной только через проперти.

Ну а в проперти можно уже добавить отладочную информацию.


Тебе показать код Оракла? Там статиков ой-ей... и падает при коннекте к 8-ке...

Ну и зачем мне код оракла? Темболее в качестве примера говнокода?

#11 
Murr патриот05.10.17 12:16
Murr
NEW 05.10.17 12:16 
в ответ Программист 05.10.17 10:37

Ну а в проперти можно уже добавить отладочную информацию.

------

Так и сделано. Там встроен аварийный подстановщик стрингбилдера.

Только проблема была именно в том, что он использовался.


Ладушки - нашел Я откуда пришла проблемка.

Дело было так: - мелкомягкие для упрощения компиляции шаблона предоставляют базовый класс с кучей функциональности.

Поменять то, что генерируется при компиляции шаблона Я "не могу". Остается - использовать функциональность того что предлагает мелкософт.

Единственное, что там можно делать - указать другой базовый класс, но класс должен предоставлять всю необходимую функциональность.


Потому делается простая генерация, из сгенерированного соурсника вырезается сгенерированный базовый класс, класс модифицируется "как надо" под задачу и подставляется в качестве базового в кучу шаблонов.


Я все сделал и на этом прокололся.

Дело в том, что в базовом классе поле под стрингбилдер есть нормальное, не статическое, поле.

Повесив на него треадстатик атрибут Я ничего не поменял.

Надо было еще и поле сделать статическим. Только тогда аттрибут переведет его в один-на-поток вариант...

Все - эта часть - работает.


Теперь надо придумать как вызывать обработчик "генерация суб-шаблоном завершена" - бо, суб-шаблоны могут быть файлогенерирующими...


Но это - не сегодня - сегодня надо починить оракловский коннект с 12-го клиента на 8-ю базу...


Ну и зачем мне код оракла?

------

А чтобы ты не кричал что статики это всегда плохо.

Могли они слепить синглетоны, но оставили статики. Ну да и фиг с ним - если бы работало - было бы даже не интересно как сделано.

А падает он не на этих статиках...

#12 
AlexNek патриот05.10.17 23:13
AlexNek
05.10.17 23:13 
в ответ Murr 05.10.17 09:48

вот как имелось в виду

public class TestInteraction : ExecutionAsync
{
  private Xxx _myThreadInstance = new Xxx();

  protected override void DoWork(object sender, DoWorkEventArgs e)
  {
     while (!CancellationPending)
     {
        //код для выполнения в потоке...
     }
  }
}

Для такого ThreadStatic совсем не нужен. Хотя похоже ты там опять что то накрутил.

#13 
Murr патриот05.10.17 23:39
Murr
NEW 05.10.17 23:39 
в ответ AlexNek 05.10.17 23:13

Это понятно.

Мне нужно, чтобы Ххх создавался вне потока и управлялся вне потока.

Бо, накладно создавать стрингбилдеры. Потому они хранятся в пуле, получаются Менеджером и им же возвращаются.


Как сейчас работает - меня устраивает.


Теперь надо думать как организовать запись результатов генерации.

Т.е. надо определять категорию шаблона - файло-генерирующий или тексто-генерирующий и писать нужное.


Вот чего пока еще не продумал до конца - какое поведение задавать. И хочется его менять... в том числе - на лету...

Ну да это не завтра.

Завтра мне Оракла мучать - надо выяснить что не так с ответом 8-ки... в 12-м клиенте.

#14 
AlexNek патриот05.10.17 23:49
AlexNek
NEW 05.10.17 23:49 
в ответ Murr 05.10.17 23:39
Мне нужно, чтобы Ххх создавался вне потока
public class TestInteraction : ExecutionAsync
{
  private Xxx _myThreadInstance;
  public TestInteraction(Xxx myThreadInstance)
  {
    _myThreadInstance = myThreadInstance;
  }

  protected override void DoWork(object sender, DoWorkEventArgs e)
  {
     while (!CancellationPending)
     {
        //код для выполнения в потоке...
     }
  }
}
#15 
Murr_0002 знакомое лицо06.10.17 11:10
Murr_0002
06.10.17 11:10 
в ответ AlexNek 05.10.17 23:49

Извини, не точно выразился.


См. аттачмент.


Там не полная картинка, но основную проблему она показывает.


В полной - шаблоны и другие ресурсы создаются вне потока .

Поток лишь выполняет работу используя предоставленные ресурсы.

В принципе, поток не знает что именно за ресурсы ему даны - СтрингБилдер вполне можно заменить фаиловым или сетевым потоком.


#16 
AlexNek патриот06.10.17 23:31
AlexNek
NEW 06.10.17 23:31 
в ответ Murr_0002 06.10.17 11:10

тут видно сразу несколько проблем:

-поток не может быть закончен когда потребуется

-паралельные потоки не должны быть зависимы один от другого

protected override void DoWork(object sender, DoWorkEventArgs e)
        {
            // none of params can be passed - only default constructor available
            T1 t1 = new T1();
            // this is the only point where assigment can be done
            t1.GenerationEnvironment = _myThreadInstance;
            // generate output by T1 & T2 (as it called in T1)
            string text = t1.TransformText();
            // in real world, unfortunetly, I need an option to write generated 
            // text to file after T2 generation complete, but before T1 will finish 
            // his work.
        }

А что мешает сделать TestInteractionT1 и TestInteractionT2 + синхронизация?

Хотя синхронизация будет чисто по времени записи.


ManualResetEvent sync = new ManualResetEvent(false);

StringBuilder myThreadInstance = ...

T1 t1 = new T1();

t1.GenerationEnvironment = myThreadInstance;

t1Thread = new TestInteractionT1(t1,myThreadInstance,sync);


T2 t2 = new T2();

t2.GenerationEnvironment = myThreadInstance;

t2Thread = new TestInteractionT2(t2,myThreadInstance,sync);

t1Thread.Start();

t2Thread.Start();

#17 
Murr_0002 знакомое лицо07.10.17 10:08
Murr_0002
07.10.17 10:08 
в ответ AlexNek 06.10.17 23:31

-паралельные потоки не должны быть зависимы один от другого

-----

Они и не зависимы.

Тебе даны всего два шаблончика для примера. В тестовой схеме, которая эмулирует возможные ситуации, их 12-ть.

В рабочей системе их у меня сейчас около 200-т... из них уровня Т1 - 2-3 десятка.

Вот для этих 2-3 десятков и делаются отдельные потоки.


-поток не может быть закончен когда потребуется

------

А поток в любом случае не может быть нормально завершен до окончания вызова т1.ТрансформТехт()

- у шаблона нет возможности терминировать выполнение метода.

А по окончании вызова - заканчивается и поток.

У менеджера - по другому - там есть возможность сделать Канцел.

С управлением можно играться довольно долго и все будет работать - проблема не в нем.


+ синхронизация?

-----

Считай так:

т1 - пишет заголовок класса и имена методов.

т2...т1000 - пишут тела методов.

кроме этих двух уровней есть еще нелимитированное вложение и рекурсивные вызовы

- типа, один из шаблонов пишет цикл, другой - иф.

Как предлагается сделать синхронизацию после окончания генерации? По времени?

Так там - параллельные потоки - нет никаких гарантий по времени...



t2Thread = new TestInteractionT2(t2,myThreadInstance,sync);

-----

Вынеси Т1 и Т2...Т1000 в отдельную ДЛЛку и работай с ней как с блакбоксом.

Базовый класс - еще в отдельную ДЛЛку.

В дополнение - Т1 - паблик, вызываемые - интернал.

В результате упрешься в задачку https://foren.germany.ru/programmer/f/32477296.html?Cat=&p...

#18 
AlexNek патриот07.10.17 16:05
AlexNek
07.10.17 16:05 
в ответ Murr_0002 07.10.17 10:08
Они и не зависимы.


т1 - пишет заголовок класса и имена методов.т2...т1000 - пишут тела методов.

что то тут противоречия в одном ответе.

Зависимости разруливаются другими методами. Не сливай всё в один котел.


#19 
Murr_0002 знакомое лицо07.10.17 17:49
Murr_0002
NEW 07.10.17 17:49 
в ответ AlexNek 07.10.17 16:05

что то тут противоречия в одном ответе.

-----

Нету там противоречия. Ибо написано:

Вот для этих 2-3 десятков и делаются отдельные потоки.


Зависимости разруливаются другими методами.

-----

Ну предложи удобную систему - Я долго подбирал что мне надо. Тот компромисс что получается вроде годится.


Не сливай всё в один котел.

-----

??? - чтобы Я делал по другому - нужно предложить лучшее решение.

Запустить каждый шаблон и суб-шаблон в своем потоке - не проблема.

Проблемой будет последующая сборка результатов... и мне ею заниматься не хочется, бо, других проблем хватает.

Так что есть шаблоны которыми может оперировать Менеджер - их и достаточно.

Чего и сколько еще есть в библиотеке шаблонов - мне и знать не хочется. Об том прогер подумал.

Тем более, что один и тот же результат можно получить бесконечным количеством способов.

#20 
AlexNek патриот07.10.17 18:36
AlexNek
NEW 07.10.17 18:36 
в ответ Murr_0002 07.10.17 17:49
Нету там противоречия. Ибо написано:Вот для этих 2-3 десятков и делаются отдельные потоки.

Это может для тебя не видно. Но если зависимостей нет, то где тогда проблема?


Зависимости разруливаются другими методами.-----Ну предложи удобную систему

у меня есть смутное предположение, что для твоих запросов и имплементаций удобной системы не существует в принципе.

Если Б должен начинаться после А, то они либо должны быть в одном потоке либо Б не должен начинаться пока А не закончит свою работу.


Не сливай всё в один котел.-----???

Ты слишком много проблем пытаешься решить за один раз.

Бери только одну проблему и решай ее.

#21 
Murr_0002 знакомое лицо07.10.17 23:57
Murr_0002
NEW 07.10.17 23:57 
в ответ AlexNek 07.10.17 18:36

Если Б должен начинаться после А,

-----

В этой терминологии - Б должен начинаться в средине А, а по окончании - продолжаться А с места останова.

Обычный вызов подпрограммы.


не существует в принципе.

-----

Хммм... но ведь работает...


Бери только одну проблему и решай ее.

-----

Я и решаю одну проблему - текущая задача - сообщить Менеджеру два факта:

1. Необходимо (или начато) выполнение суб-шаблона.

2. Выполнение суб-шаблона завершено.

Разумеется, в шаблоны ничего не добавляем...

Пока есть две идеи - сделать более сложный базовый класс или добавить треадстатик делегаты в поток...

Остальное - в процессе обдумывания.

#22 
Murr_0002 знакомое лицо07.10.17 23:59
Murr_0002
NEW 07.10.17 23:59 
в ответ AlexNek 07.10.17 18:36

где тогда проблема?

-----

Я пропустил статик в определении поля. Выше уже описано - копи-пасте, добавление атрибута и пропуск статика.

#23 
AlexNek патриот08.10.17 00:22
AlexNek
NEW 08.10.17 00:22 
в ответ Murr_0002 07.10.17 23:57
В этой терминологии - Б должен начинаться в средине А, а по окончании - продолжаться А с места останова.

Давно писал, что имплементация шаблонов у тебя "придурочная". Хотя да, по другому низзя, помню.

Поток о состоянии шаблона нифига не знает. Творческих успехов в запуске А и Б в разных потоках бебе


Хммм... но ведь работает...

Читаем внимательно что было написано. В цирке тоже многое чего работает.


Я и решаю одну проблему - текущая задача - сообщить Менеджеру два факта:

так эту проблему вообще не нужно решать, она уже решена. Всего то добавить две линии.


protected override void DoWork(object sender, DoWorkEventArgs e)
{
  _managerNotification.StartExecution();
  ...
  //string text = t1.TransformText();
  _managerNotification.StopExecution();
}

но тут же будут крики - да НО!

#24 
Murr_0002 знакомое лицо08.10.17 13:55
Murr_0002
NEW 08.10.17 13:55 
в ответ AlexNek 08.10.17 00:22

но тут же будут крики - да НО!

-----

Нее, не будет - тоже самое для Т2, плс...

#25 
AlexNek патриот08.10.17 14:36
AlexNek
NEW 08.10.17 14:36 
в ответ Murr_0002 08.10.17 13:55
тоже самое для Т2, плс...

Это те которые гуляют сами по себе и никому ничего не говорят? См. начало предыдущего ответа спок

#26 
Murr_0002 знакомое лицо08.10.17 14:47
Murr_0002
NEW 08.10.17 14:47 
в ответ AlexNek 08.10.17 14:36

Это те которые гуляют сами по себе

-----

Это те, которыми рулят другие шаблоны, а не Менеджер.


и никому ничего не говорят?

-----

Ну а как они должны говорить? Сам же говоришь - помню, что там что билли сделал, то и работает... влезть - низзя...

Но в базовый класс - можно - решение там...

#27 
AlexNek патриот08.10.17 15:24
AlexNek
NEW 08.10.17 15:24 
в ответ Murr_0002 08.10.17 14:47
Это те, которыми рулят другие шаблоны, а не Менеджер.

опять по кругу... - в потоки можно закинуть шаблоны которые не имеют зависимостей или которые можно синхронизировать.

Поэтому кидаем в поток только "главный шаблон". В принципе именно он и может знать какие его детишки могут работать впаралель, но так как он никому об этом не говорит....

Ну или со сборщиком файлов можешь развлечься.

#28 
Murr_0002 знакомое лицо08.10.17 19:58
Murr_0002
NEW 08.10.17 19:58 
в ответ AlexNek 08.10.17 15:24

Поэтому кидаем в поток только "главный шаблон". В принципе именно он и может знать какие его детишки

-----

Я, в принципе, не знаю и, в принципе, не хочу знать ничего не нужного об шаблонах.

В частности, не хочу знать какие задачи и каким методом они решают.

Нужное - есть конструктор без параметров и есть метод ТехтТрансформ() - Я знаю.

Еще есть стек с параметрами. Это - все, что Я знаю об шаблонах. Другое - не нужно -

оно создает ненужную сложность в написании шаблонов.

Есть 20-30 "главных шаблонов" - с ними работает Менеджер - распределяет имеющиеся ресурсы

и отдает свободному работнику.


могут работать впаралель

-----

Да не надо им работать в паралель. В паралель идут 10 из 20-30 "главных шаблонов" -

этого вполне хватает.


В суб-шаблонах идет генерация "тел методов".

Мягко говоря, если определен шаблон для класса А, имплементирующего интерфейс Б с

методами Ц и Д, то стоит написать шаблоны ТА, ТЦ, ТД. При желании - добавить ТБ.

Смысла выполнять ТЦ и ТД где-то параллельно с ТА нет никакого.

Ну а ТА и ТБ - "главные шаблоны" - ими будет заниматься Менеджер.


То, что мне нужно сейчас, выглядит так: ТБ не является "главным шаблоном", а вызывается

их ТА. Тем не менее, то, что сгенерилось после его вызова должно лечь в отдельный файл.

Т.е. нужно сообщить Менеджеру - "записать результат в файл"...

И проблема именно в том, что нельзя влезть в код сгенерированный для шаблона...

#29 
AlexNek патриот08.10.17 20:53
AlexNek
NEW 08.10.17 20:53 
в ответ Murr_0002 08.10.17 19:58
То, что мне нужно сейчас, выглядит так

Если думаешь что прояснил ситуацию - то это далеко не так.


ТБ вызывается из ТА - значит никаких параметров от ТБ мы не знаем. Как можно записать в файл то что неизвестно?


Да не надо им работать в паралель. В паралель идут 10 из 20-30 "главных шаблонов"

вообще то с этого и следовало начать смущ

#30 
Murr_0002 знакомое лицо08.10.17 21:34
Murr_0002
NEW 08.10.17 21:34 
в ответ AlexNek 08.10.17 20:53

значит никаких параметров от ТБ мы не знаем.

-----

Неа, не знаем... и слава богу что не знаем - они не мешают делать работу правильно.

Об нем мы знаем указанные вещи - конструктор без параметров и один метод - т.е. - знаем достаточно.


Как можно записать в файл то что неизвестно?

-----

А это как раз известно - по окончании оно сложено в зашаренный (тот самый, что Манагер отдал Рабочему) стрингбилдер.

Я думал об байт-аррай, но решил пока остаться в тексте. Поменять можно позднее, это не сложно...


вообще то с этого и следовало начать

-----

Так оно давно написано и несколько раз повторено. Наконец - еще и понято. спок

#31 
AlexNek патриот08.10.17 22:21
AlexNek
NEW 08.10.17 22:21 
в ответ Murr_0002 08.10.17 21:34
А это как раз известно - по окончании оно сложено в зашаренный (тот самый, что Манагер отдал Рабочему) стрингбилдер.

ладно, не будем узнавать как то, что ТА вызвал ТБ стало известно манагеру (и кто такой Рабочий). Но если стало известно, то в чем проблема записать енто в файл?


Так оно давно написано и несколько раз повторено

Странно, как то не заметил смущ


Наконец - еще и понято.

Вот в этом вы батенька глубоко ошибаетесь.

Я уж давно не пытаюсь сложить общей картины из твоих задачек, потому как ни разу еще не получилось хммм

Пользуем то чем кормят.

#32 
Murr_0002 знакомое лицо08.10.17 23:30
Murr_0002
NEW 08.10.17 23:30 
в ответ AlexNek 08.10.17 22:21

не будем узнавать как то, что ТА вызвал ТБ стало известно манагеру

------

В том то и дело, что еще не стало известно. Равно как не решено надо ли и как сообщать тоже самое об ТА.

Сделать это и есть текущая задача...


Все, бай-бай пора...

#33 
AlexNek патриот08.10.17 23:47
AlexNek
NEW 08.10.17 23:47 
в ответ Murr_0002 08.10.17 23:30
Я и решаю одну проблему - текущая задача - сообщить Менеджеру два факта:
Сделать это и есть текущая задача...

что то часто меняются текущие задачи смущ


А это как раз известно - по окончании оно сложено в зашаренный (тот самый, что Манагер отдал Рабочему) стрингбилдер.
В том то и дело, что еще не стало известно.

Так - или спать или запутывать бебе

#34 
1 2 все