Вверх ↑
Этот топик читают: Гость
Ответов: 3825
Рейтинг: 620
#46: 2019-01-10 17:01:01 ЛС | профиль | цитата
Пример №1 работы параллельного потока:


Add(MainForm,8308775,154,126)
{
Height=214
Caption="Encrypt - threads demo"
BorderStyle=1
Position=1
}
Add(Edit,4011429,245,126)
{
Left=60
Top=5
Width=320
Text="123456"
}
Add(Label,15199179,245,77)
{
Left=10
Top=10
Width=48
Height=17
Caption="Пароль:"
}
Add(LineBreakEx,3037814,245,168)
{
Caption="pass"
Type=3
link(_Data,4011429:Text,[])
}
Add(Label,5968536,511,77)
{
Left=10
Top=35
Width=87
Height=17
Caption="Исходный файл:"
}
Add(Label,3369797,707,77)
{
Left=10
Top=75
Width=121
Height=17
Caption="Зашифрованный файл:"
}
Add(Button,5726157,147,581)
{
Left=10
Top=120
Width=95
Height=25
Caption="Зашифровать"
link(onClick,1595303:doStart,[])
}
Add(Label,14925684,756,574)
{
Left=80
Top=155
Width=10
Height=17
Caption="0"
}
Add(LineBreakEx,9758177,434,511)
{
Caption="fsrc"
Type=2
}
Add(LineBreakEx,5516860,441,532)
{
Caption="fencr"
Type=2
}
Add(LineBreakEx,10668305,427,490)
{
Caption="pass"
Type=2
}
Add(EnCrypt,13958992,420,574)
{
Mode=4
InitVector="AAA"
BufferSize=5242880
Point(onError)
Point(doAbort)
Point(onProgress)
link(onEncrypt,14941371:doWork2,[])
link(Key,10668305:getVar,[])
link(SrcFileName,9758177:getVar,[])
link(DstFileName,5516860:getVar,[])
link(onError,8933103:doMessage,[])
link(onProgress,14941371:doWork3,[(473,594)])
}
Add(Message,8933103,490,581)
{
Caption="Ошбика"
Icon=1
}
Add(Button,7998221,350,595)
{
Left=235
Top=150
Width=105
Caption="Прервать"
link(onClick,13958992:doAbort,[])
}
Add(HubEx,14941371,469,574)
{
link(onEvent,11140347:doSynchronize,[])
}
Add(Thread,1595303,217,581)
{
FastStop=0
link(onExec,13958992:doEncryptFile,[])
}
Add(Synchronize,11140347,707,574)
{
link(onSync,14925684:doText,[])
}
Add(Edit,824952,511,140)
{
Left=10
Top=50
Width=330
Text="bigfile.avi"
}
Add(Button,15277380,413,140)
{
Left=345
Top=50
Width=40
Caption="..."
link(onClick,1218516:doExecute,[])
}
Add(ODialog,1218516,469,140)
{
Filter="Все файлы (*.*)|*.*"
Title="Выбор файла"
FileName=""
Point(FileName)
link(onExecute,824952:doText,[])
link(FileName,12181497:Var3,[(475,125)(551,125)(551,187)])
}
Add(Edit,12991863,707,140)
{
Left=10
Top=95
Width=330
Text="bigfile.avi.encrypted"
}
Add(Button,4070287,609,140)
{
Left=345
Top=95
Width=40
Caption="..."
link(onClick,2080759:doExecute,[])
}
Add(ODialog,2080759,665,140)
{
Filter="Все файлы (*.*)|*.*"
Title="Выбор файла"
FileName=""
Point(FileName)
link(onExecute,12991863:doText,[])
link(FileName,10205981:Var3,[(671,121)(752,121)(752,180)])
}
Add(GetDataEx,10205981,707,175)
{
link(Data,12991863:Text,[])
}
Add(GetDataEx,12181497,511,182)
{
link(Data,824952:Text,[])
}
Add(LineBreakEx,9353820,511,203)
{
Caption="fsrc"
Type=3
link(_Data,12181497:Var2,[])
}
Add(LineBreakEx,1787963,707,196)
{
Caption="fencr"
Type=3
link(_Data,10205981:Var2,[])
}
Add(Label,6318026,154,210)
{
Left=10
Top=155
Width=68
Height=17
Caption="Обработано:"
}
Add(InfoTip,8165527,322,385)
{
Info=#207:Более правильно сначала через Synchronize (либо сразу по клику на кнопку) получить требуемые данные от визуальных компонентов в переменные, затем уже без Synchronize в параллельном потоке запустить обработку|
Width=253
Height=172
}
Add(InfoTip,2621263,651,490)
{
Info=#54:Обращаться к визуальным компонентам нужно только через|11:Synchronize|
Width=190
Height=151
}
Add(InfoTip,7225840,252,280)
{
Info=#10:Паттерн №1|84:Миниально корректное оповещение пользователя о прогрессе работы параллельного потока|
Font=[MS Sans Serif,8,1,0,1]
Width=393
Height=53
}
Здесь всё хорошо, но чем быстрее выдаются события EnCrypt.onEncrypt (например, от перехода с HDD на SSD или при уменьшении EnCrypt.BufferSize), тем более "дорогостоящим" оказывается вывод прогресса в Label, более тормознутым стаёт интерфейс, больше времени затрачивается на вывод, чем на саму обработку.
nesco писал(а):
у тебя никогда не возникало сомнения в точке Busy?
Думаю... Подумал.
Как по мне, так назначение этой точки - ровно то, что написано в её описании: "узнать, работает ли ещё поток, или уже завершился" (если это зачем-то нужно). А чем в это время он занимается (стоит ли на задержке, или качает файл из сети) - не важно: он занимается тем, что мы на него возложили (задержку и скачивание).
nesco писал(а):
мы могли бы свободно обращаться к данным параллельных потоков, пока те спят
Так в том то и дело что не могли. Потому что ошибки проявляются ровно в тот момент когда один поток "обращается к данным", а другой в этот же момент "просыпается" и пишет их. Задержка просто влияет на вероятность. А вот то "кольцо опроса" просто вносит дополнительный фактор неопределенности.

С другой стороны предложенный тобой пример использования вполне безопасно заменяется таймером в качестве "кольца опроса" и 2-мя SafeMode на чтение/запись данных для защиты данных при соместном доступе. Как раз хочу показать во втором "паттерне".

--- Добавлено в 2019-01-10 17:54:43

Пример №2 - правильное отображение прогресса работы параллельного потока:


Add(MainForm,8308775,154,126)
{
Height=214
Caption="Encrypt - threads demo"
BorderStyle=1
Position=1
}
Add(Edit,4011429,245,126)
{
Left=60
Top=5
Width=320
Text="123456"
}
Add(Label,15199179,245,77)
{
Left=10
Top=10
Width=48
Height=17
Caption="Пароль:"
}
Add(LineBreakEx,3037814,245,168)
{
Caption="pass"
Type=3
link(_Data,4011429:Text,[])
}
Add(Label,5968536,511,77)
{
Left=10
Top=35
Width=87
Height=17
Caption="Исходный файл:"
}
Add(Label,3369797,707,77)
{
Left=10
Top=75
Width=121
Height=17
Caption="Зашифрованный файл:"
}
Add(Button,5726157,140,819)
{
Left=10
Top=120
Width=95
Height=25
Caption="Зашифровать"
link(onClick,1595303:doStart,[])
}
Add(Label,14925684,854,1036)
{
Left=80
Top=155
Width=10
Height=17
Caption="0"
link(Text,3557433:Value,[])
}
Add(LineBreakEx,9758177,490,546)
{
Caption="fsrc"
Type=2
}
Add(LineBreakEx,5516860,497,567)
{
Caption="fencr"
Type=2
}
Add(LineBreakEx,10668305,483,525)
{
Caption="pass"
Type=2
}
Add(EnCrypt,13958992,476,819)
{
Mode=4
InitVector="AAA"
Point(onError)
Point(doAbort)
Point(onProgress)
link(onEncrypt,14941371:doWork2,[])
link(Key,10668305:getVar,[])
link(SrcFileName,9758177:getVar,[])
link(DstFileName,5516860:getVar,[])
link(onError,11356253:doEvent1,[])
link(onProgress,14941371:doWork3,[(529,839)])
}
Add(Message,8933103,595,854)
{
Caption="Ошбика"
Icon=1
}
Add(Button,7998221,336,847)
{
Left=235
Top=150
Width=105
Caption="Прервать"
link(onClick,4116247:doEvent1,[])
}
Add(HubEx,14941371,525,819)
{
link(onEvent,15768141:doSafeMode,[])
}
Add(Thread,1595303,210,819)
{
FastStop=0
link(onExec,9160381:doEvent1,[])
}
Add(Edit,824952,511,140)
{
Left=10
Top=50
Width=330
Text="bigfile.avi"
}
Add(Button,15277380,413,140)
{
Left=345
Top=50
Width=40
Caption="..."
link(onClick,1218516:doExecute,[])
}
Add(ODialog,1218516,469,140)
{
Filter="Все файлы (*.*)|*.*"
Title="Выбор файла"
FileName=""
Point(FileName)
link(onExecute,824952:doText,[])
link(FileName,12181497:Var3,[(475,125)(551,125)(551,187)])
}
Add(Edit,12991863,707,140)
{
Left=10
Top=95
Width=330
Text="bigfile.avi.encrypted"
}
Add(Button,4070287,609,140)
{
Left=345
Top=95
Width=40
Caption="..."
link(onClick,2080759:doExecute,[])
}
Add(ODialog,2080759,665,140)
{
Filter="Все файлы (*.*)|*.*"
Title="Выбор файла"
FileName=""
Point(FileName)
link(onExecute,12991863:doText,[])
link(FileName,10205981:Var3,[(671,121)(752,121)(752,180)])
}
Add(GetDataEx,10205981,707,175)
{
link(Data,12991863:Text,[])
}
Add(GetDataEx,12181497,511,182)
{
link(Data,824952:Text,[])
}
Add(LineBreakEx,9353820,511,203)
{
Caption="fsrc"
Type=3
link(_Data,12181497:Var2,[])
}
Add(LineBreakEx,1787963,707,196)
{
Caption="fencr"
Type=3
link(_Data,10205981:Var2,[])
}
Add(Label,6318026,154,210)
{
Left=10
Top=155
Width=68
Height=17
Caption="Обработано:"
}
Add(InfoTip,8165527,378,420)
{
Info=#207:Более правильно сначала через Synchronize (либо сразу по клику на кнопку) получить требуемые данные от визуальных компонентов в переменные, затем уже без Synchronize в параллельном потоке запустить обработку|
Width=253
Height=172
}
Add(LineBreakEx,6229770,357,707)
{
Caption="start"
}
Add(LineBreakEx,5156901,637,1036)
{
Caption="start"
Type=1
link(OnEvent,15007035:doTimer,[])
}
Add(InfoTip,7225840,252,294)
{
Info=#10:Паттерн №2|124:Уменьшен EnCrypt.BufferSize для ускорения выдачи событий и показано способ реализации оповещения пользователя в таком случае|
Font=[MS Sans Serif,8,1,0,1]
Width=442
Height=60
}
Add(Memory,3557433,854,819)
{
}
Add(SafeMode,15768141,784,819)
{
Name="CritSection1"
link(onSafeMode,3557433:doValue,[])
AddHint(-20,36,72,13,Name)
}
Add(SafeMode,15450595,791,1036)
{
Name="CritSection1"
link(onSafeMode,14925684:doText,[])
AddHint(-23,36,72,13,Name)
}
Add(InfoTip,16259543,749,770)
{
Info=#74:Данные, к которым обращаются несколько потоков, должны защищаться SafeMode|0:|0:|0:|0:|0:|0:|43:Здесь не следует заграгивать главный поток!|
Width=190
Height=151
}
Add(LineBreakEx,5684143,322,966)
{
Caption="stop"
}
Add(LineBreakEx,2541384,637,1057)
{
Caption="stop"
Type=1
link(OnEvent,15007035:doStop,[(691,1063)(691,1049)])
}
Add(Timer,15007035,700,1036)
{
Interval=500
Enable=1
link(onTimer,15450595:doSafeMode,[])
AddHint(-4,41,33,13,Interval)
}
Add(Hub,9160381,266,819)
{
OutCount=3
link(onEvent1,7172380:doSynchronize,[(294,825)(294,713)])
link(onEvent2,13958992:doEncryptFile,[])
link(onEvent3,5684143:doWork,[(293,839)(293,972)])
}
Add(Synchronize,7172380,308,707)
{
link(onSync,6229770:doWork,[])
}
Add(InfoTip,15317784,231,672)
{
Info=#64:Здесь Synchronize требуется для включения таймера из пар. потока|
Width=190
Height=81
}
Add(LineBreakEx,12946360,595,826)
{
Caption="stop"
}
Add(Hub,11356253,553,826)
{
link(onEvent1,12946360:doWork,[])
link(onEvent2,8933103:doMessage,[(582,839)(582,860)])
}
Add(LineBreakEx,13326123,406,847)
{
Caption="stop"
}
Add(Hub,4116247,378,847)
{
link(onEvent1,13326123:doWork,[])
link(onEvent2,13958992:doAbort,[(459,860)(459,846)])
}
Add(InfoTip,10198054,616,994)
{
Info=#28:Исполняется в главном потоке|
Width=281
Height=123
}
Add(InfoTip,2406579,308,896)
{
Info=#228:Поскольку таймер показывает пользователю прогресс с некоторым интервалом, то последнее значение (100%) пользователь может не увидеть - по завершению работы можно принудительно через Synchronize ещё раз вывести последнее значение|
Width=274
Height=102
}
- главный поток не перегружается вызовами из параллельного, а работает ровно с той нагрузкой, которую мы задали интервалом таймера и тяжестью выполняемой этим таймером работы. Независимо от загруженности параллельного потока.
- параллельный поток работает с максимальным быстродействием, не ограничиваясь скоростью работы визуальных компонентов. Можно предположить что есть некоторые издержки при "маршрутизации" системой потоков внутри критической секции, но они несущественны. Более важную роль играет трудоемкость действий, которые внутри этой секции происходят - следует минимизировать.

Хотите увидеть deadlock? Поставьте на выходе из Memory поле ввода Edit (или Synchronize) и уменьшите интервал таймера. Это кстати к вопросу о "вероятности ошибок" при использовании задержек - интервалом таймера можно добиться что программа какое-то время будет работать без deadlock. Но в какой-то момент все равно зависнет.

Редактировалось 7 раз(а), последний 2019-01-10 18:02:14
карма: 17

0
Разработчик
Ответов: 25329
Рейтинг: 2070
#47: 2019-01-10 17:59:35 ЛС | профиль | цитата
Netspirit, это все хорошо, но вот нарисуй ты свое видение работы нескольких потоков, не одного, а минимум трех-четырех, те мультипоточный режим
карма: 19

0
Ответов: 3825
Рейтинг: 620
#48: 2019-01-10 18:06:34 ЛС | профиль | цитата
Так сходу конкретный пример не приходит в голову, но суть остаётся та же:
- доступ к интерфейсным компонентам - только через Synchronize
- минимизация загрузки главного потока из параллельных
- доступ к общим данным защищен SafeMode
- по SafeMode в параллельном потоке нельзя дергать главный поток никаким образом
карма: 17

0
Разработчик
Ответов: 25329
Рейтинг: 2070
#49: 2019-01-10 18:08:23 ЛС | профиль | цитата
Netspirit писал(а):
доступ к общим данным защищен SafeMode

А разве наш SafeMode поддерживает мультипоточность?
карма: 19

0
Ответов: 3825
Рейтинг: 620
#50: 2019-01-10 18:11:06 ЛС | профиль | цитата
Не совсем понятен вопрос. Он, собственно, для показанных мной целей и предназначен, и именно в многопоточных приложениях. Если будут какие-то ошибки - значит, вопрос в реализации кода, можно исправить.

Редактировалось 1 раз(а), последний 2019-01-10 18:11:31
карма: 17

0
Разработчик
Ответов: 25329
Рейтинг: 2070
#51: 2019-01-10 18:16:45 ЛС | профиль | цитата
Netspirit писал(а):
Если будут какие-то ошибки - значит, вопрос в реализации кода, можно исправить.

Ты посмотри, если не трудно

--- Добавлено в 2019-01-10 18:21:12

Netspirit, ты вроде где-то кидал схемку с ожиданием завершения работы всех потоков, или я че-то путаю? Вспомнил, это был пример для WaitMultiple. А как все это безобразие приобщить к динамике, те если мне неизвестно изначальное количество потоков, это вообще можно реализовать по такому принципу, те через Event?

Редактировалось 3 раз(а), последний 2019-01-10 19:20:26
карма: 19

0
Ответов: 687
Рейтинг: 7
#52: 2019-01-10 20:26:09 ЛС | профиль | цитата
Во втором примере не лучше поставить таймеру в сейфмод NoWait? Ведь Wait подвесит главный поток до освобождения ресурса.

Редактировалось 1 раз(а), последний 2019-01-10 20:52:40
карма: 0

0
Ответов: 3825
Рейтинг: 620
#53: 2019-01-11 12:43:47 ЛС | профиль | цитата
nesco писал(а):
А как все это безобразие приобщить к динамике, те если мне неизвестно изначальное количество потоков
Предполагаю: получить произвольное количество потоков можно только когда у нас есть динамический контейнер, в котором создаются и уничтожаются потоки? А ожидает завершения этих потоков кто-то извне, кто добавляет экземпляры контейнера, стартует их и, вероятно, отвечает за уничтожение.

Как я это понимаю.
Первое. У нас в каждый момент времени "активной" может быть только одна копия схемы - именно с ней мы работаем, когда используем внешние точки контейнера. Значит для того, чтобы "проверить состояние" каждой из схем (завершила ли она свою работу или нет), нам нужно перебрать их все извне. Сам по себе этот процесс геморройный, а результатом его работы может быть, скажем, массив хендлов компонентов Events в каждой из схем (а если у компонента Thread вывести точку Handle, то можно обойтись без Events - на ней тоже можно делать ожидание). Как ты и сказал, компонент WaitMultiple в этом случае не поможет (можно, конечно, в WaitMultiple задать заведомо максимальное количество верхних точек, к ним сверху навесить вложенную схему, которая полученный ранее "вертикальный" массив хендлов будет "раскладывать горизонтально" для подачи на точки WaitMultiple).

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

Третье. Самое актуальное и в данный момент не решенное - безопасное удаление копии схемы в контейнере, когда внутри работает параллельный поток. Очевидно, уничтожение во время работы потока неминуемо приведет к ошибке. Значит поток нужно остановить и дождаться его завершения. Как? Terminate потока в принципе недопустимо (никогда). Значит, решение - выставить каждой копии в схеме извне флаг "прекратить работу" и дождаться завершения всех потоков. Возвращемся к твоему вопросу: "как узнать, что все потоки в контейнере завершили работу?".

Вероятно, решение - тут требуется ещё один компонент по типу Events - семафор.
Принцип работы такой. Хендл семафора изначально находится в состоянии "non-signalled". Каждый поток при старте вызывает метод компонента, скажем, doAquire. Когда поток завершает свою работу, он вызывает его же метод doRelease. А внутри компонента есть объект Event и потокобезопасный счетчик. doAquire увеличивает счетчик, doRelease - уменьшает. Как только счетчик уменьшается до 0 - значит все потоки завершили работу, внутренний Event переводится в состояние "signalled". Теперь внешний по отношению к контейнеру поток может делать WaitObject на хендле данного семафора и возобновить работу, когда все потоки завершились.

Как понятно из описания, этот принцип вполне реализуется существующими компонентами: один CounterEx + Events, одноименный SafeMode у всех потоков на увеличение и уменьшение счетчика, и внешний поток с помощью WaitObject ожидает сигнала от Events. CounterEx сигналит Events, когда дошел до 0.

--- Добавлено в 2019-01-11 12:59:34

Neo писал(а):
Во втором примере не лучше поставить таймеру в сейфмод NoWait?
Если устраивает пропуск событий таймера - можно поставить. А если события параллельного потока достаточно частые, то ты рискуешь вообще непонятно когда успешно попасть таймером в критическую секцию. И чтобы попадать "чаще" тебе придется таймер значительно ускорить. Что само по себе приводит к более частой обработке главным потоком сообщений таймера.
Но дело в том что раз я обращаюсь к данным - значит они мне нужны, тогда я жду их доступности.
Neo писал(а):
Ведь Wait подвесит главный поток до освобождения ресурса.
Поэтому я в предыдущих постах упоминал частоту обращения к главному потоку и тяжесть задач выполняемых при таких обращениях. Скажем, в моем примере для информирования пользователя я поставил таймер на 500 мс. Мог бы и на 1000 - для меня это нисколько не хуже. При этом: сообщения в главный поток приходят 2 раза в секунду (или 1 раз) - это абсолютно не накладно: ты когда мышкой проводишь по окну, то у тебя в главный поток приходит сообщение чуть ли не на каждый пиксель перемещения, но это незаметно - ибо на событие мышки у тебя нет громоздкой обработки, то-есть, то что я называл "тяжесть обработки".
Так вот, заход в SafeMode 2 раза в секунду, чтение переменной и вывод её в Label - это вообще не нагрузка, даже не смотря на ожидание главного потока на SafeMode:
- параллельный поток занимает SafeMode
- главный поток стаёт на ожидание
- параллельный поток устанавливает значение Memory и покидает SafeMode (а тут уже играет роль упомянутая мной "минимизация работы, выполняемой потоками внутри SafeMode" - и это понятно: другие же потоки в это время ждут).
- после чего в SafeMode пропускается главный поток (а параллельный поток на следущем входе в SafeMode стаёт в ожидание, чтобы не нарушить данные, пока их читает другой поток).

Редактировалось 7 раз(а), последний 2019-02-04 13:27:41
карма: 17

0
Разработчик
Ответов: 25329
Рейтинг: 2070
#54: 2019-01-11 13:30:47 ЛС | профиль | цитата
Netspirit писал(а):
Как понятно из описания, этот принцип вполне реализуется существующими компонентами: один CounterEx + Events, одноименный SafeMode у всех потоков на увеличение и уменьшение счетчика, и внешний поток с помощью WaitObject ожидает сигнала от Events. CounterEx сигналит Events, когда дошел до 0.

КМК, все же лучше это сделать отдельным компонентом
карма: 19

0
Ответов: 3825
Рейтинг: 620
#55: 2019-01-11 13:42:21 ЛС | профиль | цитата
Потоки в контейнере должны будут делать два выхода из контейнера на увеличение и уменьшение счетчика. Каждый выход из контейнера все равно должен будет оформлен SafeMode.

Можно сделать ещё один тип динамического контейнера "потокобезопасный", когда в коде контейнера уже применяется критическая секция при активизиции/добавлении/уничтожении копии внутренней схемы. Но тут тоже есть потенциальные комбинации с deadlock - если внутри перед выходом или снаружи после выхода параллельный поток обращается к главному потоку, а главный поток обращается в это время к контейнеру, входы которого тоже защищены критической секцией. Требуется очень много думать. И главное - иметь примеры для тестирования.

Редактировалось 1 раз(а), последний 2019-01-11 14:03:31
карма: 17

0
Разработчик
Ответов: 25329
Рейтинг: 2070
#56: 2019-01-11 14:18:41 ЛС | профиль | цитата
Netspirit писал(а):
Как понятно из описания, этот принцип вполне реализуется существующими компонентами: один CounterEx + Events, одноименный SafeMode у всех потоков на увеличение и уменьшение счетчика, и внешний поток с помощью WaitObject ожидает сигнала от Events. CounterEx сигналит Events, когда дошел до 0.

А можешь накатать примерную схемку с реализацией через рассыпуху?
карма: 19

0
Ответов: 3825
Рейтинг: 620
#57: 2019-01-11 14:32:06 ЛС | профиль | цитата
nesco писал(а):
А можешь накатать примерную схемку с реализацией через рассыпуху?
Ха! Если сделаешь нормальный Events.
Сейчас для начала пробую тестовую схему с контейнером и потоками сделать, чтобы было на чем пробовать.
карма: 17

0
Ответов: 687
Рейтинг: 7
#58: 2019-01-11 14:35:33 ЛС | профиль | цитата
Netspirit писал(а):
Так вот, заход в SafeMode 2 раза в секунду, чтение переменной и вывод её в Label - это вообще не нагрузка, даже не смотря на ожидание главного потока на SafeMode:

А если такую развязку потоков я ставлю в самом начале обработки (в частности по получению события из Вашего компонента TCP в мультипоточном режиме)? Там сейфмод будет относительно долго работать после. Выходит нужно ставить двойную развязку сразу: одна с совместным доступом по сейфмод, а другая сразу за ней без сейфмод с таким же стеком и чтением по таймеру?
карма: 0

0
Разработчик
Ответов: 25329
Рейтинг: 2070
#59: 2019-01-11 14:37:23 ЛС | профиль | цитата
Netspirit писал(а):
Если сделаешь нормальный Events

Ты же вроде уже его правил и что-то мы уже обновляли?
карма: 19

0
Ответов: 3825
Рейтинг: 620
#60: 2019-01-11 14:40:37 ЛС | профиль | цитата
Я правил, показывал. Но так и не приняли: /topic/57987/4#p269657

Neo писал(а):
Там сейфмод будет относительно долго работать после.
Всё же надо пытаться минимизировать. Скажем, может быть несколько независимых участков с отдельными именами SafeMode. То-есть, взаимно ожидают только одноименные SafeMode.
Neo писал(а):
Выходит нужно ставить двойную развязку сразу
Не знаю. Тут надо разбираться в конкретной схеме.



А у нас есть ещё компонент MutexThread - я не знаю как им пользоваться...

Редактировалось 2 раз(а), последний 2019-01-11 14:50:12
карма: 17

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)