
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

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 переменную
И использовать ее для передачи данных между потоками, а сокеты использовать исключительно для отправки сигнала на вычитку данных для него

Evil
03.11.2017
18:21:59

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

Andrey
03.11.2017
19:47:36
про то же

?
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

Oleg
04.11.2017
15:13:14

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
протестирую еще, там выше пример видел

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

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

Just
04.11.2017
15:28:15

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

Just
04.11.2017
15:34:15

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;
}?