@dlangru

Страница 308 из 719
qwerty
03.11.2017
12:43:17
вообще действительно непонятно. Неужели к synchronized классу надо еще какой-нибудь mutex?

Ievgenii
03.11.2017
12:43:44
Так это и есть обвертка над мютексом

qwerty
03.11.2017
12:45:25
так я вот и думаю

Just
03.11.2017
12:45:39
так да, synchronized нормально работает с обычными типами, хотя даже для сложения нужно делать вот так test.atomicOp!"+="(4);

Google
Just
03.11.2017
12:46:00
и вот такого же аналога для insertFront нету, я так понимаю

делаю вот так synchronized class SocksQueue{ private DList!string _queue; public void push(string data) { _queue.insertFront(data); } public string pop() { auto res = _queue.back(); _queue.removeBack(); return res; } }

https://tour.dlang.org/tour/en/multithreading/synchronization-sharing я много раз смотрел ссылку, но не обращал внимания на примеры кода справа, а там прямо таки класс SafeQueue описан и прочие отличные вещи)

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

qwerty
03.11.2017
13:40:49
через message passing может быть race conditions

?

ну вроде нет гонок

можно заюзать, если архитектура позволяет

Just
03.11.2017
15:11:00
через message passing может быть race conditions
а что это такое? message passing

qwerty
03.11.2017
15:16:38
Есть два подхода обмена данными. Lock data и message passing. То что вы хотите - Lock data. Message passing когда передаются данные по каналам.

Сейчас пример дам

https://tour.dlang.org/tour/en/multithreading/message-passing

Ievgenii
03.11.2017
16:25:43
Ну такой себе подход. Тред же при этом блокируется

Google
Ievgenii
03.11.2017
16:25:58
И.к. функция ресив блокирующая

Я предпочитаю пейр сокет

Это может позволить общаться с любым тредом и не блокировать его

Just
03.11.2017
16:53:48
qwerty
03.11.2017
16:59:20
Ievgenii
03.11.2017
17:35:54
Да ладно!

Блокирующая

Сейчас тест напишу

module test; import std.stdio; import std.concurrency; import core.thread; // ... void main() { auto worker = spawn(&workerFunc); worker.send(1); Thread.sleep(3.seconds); worker.send(2); Thread.sleep(3.seconds); worker.send(0); } void workerFunc() { bool end = false; while (!end) { writeln("tick"); receive(delegate(int t){ writeln(t); if (t == 0){ writeln("end"); end = true; } }); } }

Если бы функция receive была бы не блокирующей, мы бы ОЧЕНЬ много раз видели бы в логах строку "tick"

Но мы видем ее только тогда, когда отсылаем сообщение потоку

Так что эта функция блокирующая

Что не позволяет использовать новый поток как полноценный независимый поток обработки данных

А получаем поток, который ждет указаний на выполнение.

Конечно, иногда это очень даже подходит

Если делаешь что-то типа своих куратин

В зависимости от полученных данных - выполняешь какие-то действия

НО! Ответ от этого потока мы можем получить тоже только блокирующи

Соответственно для подобных вещей он не сильно то уж и подходит

А вот пейрСокет - открываешь их, а после стартуешь поток. Первый сокет в родителе, второй в дочернем потоке

Google
Ievgenii
03.11.2017
17:44:51
И реализуешь IPC через него

Хочешь - гоняй данные даже через него

Но легче сделать для этого или шейред память

Или просто __gshared переменную

И использовать ее для передачи данных между потоками, а сокеты использовать исключительно для отправки сигнала на вычитку данных для него

Ievgenii
03.11.2017
18:22:42
После пихаешь этот сокет в общий луп

И все...

Evil
03.11.2017
18:31:11
@devBocharov покури эти советы. Завтра попробуем на деле :)

qwerty
03.11.2017
19:30:58
что-то я не понял видимо о чем речь. Да, receive вперед другой receive не побежит, но другие потоки останавливать не станет

но это как раз то, что надо

в потоках делаешь что-то с объектом, а в receive кладешь его в контейнер

Ievgenii
03.11.2017
19:33:02
Ну смотри

Это приведет к тому, что ты, скажем, не сможешь обрабатывать в этом потоке входные соединения

Если этот новый поток нужен исключительно для того, чтобы осуществить одну обработку - то норм

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

qwerty
03.11.2017
19:44:24
Честно сказать, не могу понять о чем речь. Есть вот еще какой вариант https://run.dlang.io/gist/3afff560fe3b2f439272c3ee3adcebd0?compiler=dmd можно избавиться от shared через cast. А гарантию того, что данные будут меняться только в одном потоке вы даете через syncronized класса и приватность этого поля

Andrey
03.11.2017
19:46:41
или атомарный флаг

qwerty
03.11.2017
19:47:02
или атомарный флаг
это про что Вы?

Google
?
03.11.2017
20:42:45
В начале faq на сайте выглядел холиваристо, теперь это просто толстый тролинг, разочерование

Ievgenii
03.11.2017
21:36:27
Зачем?

Можно вообще без него писать, если его гарантированно его меняет только один поток

кстати можно также передать сообщение
Можно, но это нужно ещё сериализацию писать, а на это уйдет память и время

А так у тебя уже есть этот объект в памяти

Admin
ERROR: S client not available

Ievgenii
03.11.2017
21:41:03
кстати можно также передать сообщение
Немного не так понял Ваше сообщение сначало. Конечно можно, но при этом родительский тред будет заблокирован в ожидании ответа от дочернего.

https://github.com/LLC-CERERIS/big.d/blob/dev/README.md

Но он тоже базируется на vibe...

qwerty
04.11.2017
14:06:05
@devBocharov https://forum.dlang.org/post/mailman.921.1509747928.3360.digitalmars-d-learn@puremagic.com

Just
04.11.2017
14:35:36
@devBocharov https://forum.dlang.org/post/mailman.921.1509747928.3360.digitalmars-d-learn@puremagic.com
спасибо, т.е. любая работа с shared объектом должна проходить в вот таких synchronized блоках? понятно, а что там за mutexForMySharedObject? shared(DList!string) sharedDlist; Mutex mutexForSharedDlist; void main(){ synchronized(mutexForSharedDlist) { auto queue = cast(DList!string)sharedDlist; queue.insertFront("a"); } } в таком виде ошибку Segmentation fault (core dumped) выдает, а если просто shared(DList!string) sharedDlist; void main(){ synchronized { auto queue = cast(DList!string)sharedDlist; queue.insertFront("a"); } } то норм

qwerty
04.11.2017
14:40:29
> спасибо, т.е. любая работа с shared объектом должна проходить в вот таких synchronized блоках? для избежания гонки данных

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

Oleg
04.11.2017
15:01:50
synchronized просто синхронизирует)

Использует mutex класса

Так же, если используются несколько mutex'ов фиксирует последовательность их захвата: два потока хотят захватывать A и B, но в одном было написано synchronized(A,B), в другом synchronized(B, A) - в обычном языке привело бы к deadlock, в D не будет, так как они будут всегда захватываются в одном порядке вне зависимости от написания в коде

Just
04.11.2017
15:09:32
Использует mutex класса
а как его использовать правильно в этому случае? вот так та же ошибка class Queue { private DList!string socksQueue; Mutex mtxQueue; } shared(Queue) sharedQueue; void main(){ synchronized(sharedQueue.mtxQueue) { auto queue = cast(Queue)sharedQueue; } есть такой пример https://dlang.org/phobos/core_sync_mutex.html, но тут без synchronized

Google
qwerty
04.11.2017
15:14:38
я не ссылку вчера отправил

вот правильная https://run.dlang.io/gist/320567145bd5fb985429c6ba28c7ce00?compiler=dmd

Ievgenii
04.11.2017
15:17:49
Синхронайз - это обвертка над мьютексом

Можете сами это делать

Но те данные, к которым хотите получить доступ - должны быть сшейред

Ну или __gshared

Для тех, кто целеком и полностью понимает, что он делает

Just
04.11.2017
15:25:35
вот правильная https://run.dlang.io/gist/320567145bd5fb985429c6ba28c7ce00?compiler=dmd
synchronized class SocksQueue { private DList!string _queue; public void push(string data) { (cast(DList!string) _queue).insertFront(data); } } void main(){ auto s = new shared SocksQueue(); s.push("a"); да, так работает, спасибо еще раз т.е. это правильная реализация такого класса?

протестирую еще, там выше пример видел

qwerty
04.11.2017
15:26:53
Да, потому что мы гарантируем отсутствие гонки данных через synchronized

Pavel
04.11.2017
15:26:58
По идее да

Можешь поставить в начале и конце void push(string data) какой нибудь слип секунд на 5 и посмотреть как в секцию будут входить разные треды.

Pavel
04.11.2017
15:29:11
И тогда мне интересно, будет ли это работать в случае файберов. Думаю что нет, т.к. файбер не может заблокироваться и ждать освобождения секции, ведь он также остановит все другие файберы в треде.

Для них получается нужен специальный файберный мьютекс?

Just
04.11.2017
15:34:15
Можешь поставить в начале и конце void push(string data) какой нибудь слип секунд на 5 и посмотреть как в секцию будут входить разные треды.
synchronized class SocksQueue { private DList!string _queue; public void push(string data) { writeln("push "~data); Thread.sleep(5.seconds); (cast(DList!string) _queue).insertFront(data); } } void main(){ auto queue = new shared SocksQueue(); queue.push("1"); new Thread({ queue.push("2"); }).start(); задержка есть

Pavel
04.11.2017
15:34:49
Круто значит работает )

Just
04.11.2017
16:18:29
да, отлично, большое всем спасибо?

Oleg
04.11.2017
16:36:31
Pavel
04.11.2017
16:43:01
типа while(mutex.isLocked) { yield; }?

Страница 308 из 719