Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Фреймворк распределенного приложения 
:(
    Опции темы
drug007
Дата 11.1.2013, 09:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



Помогите оценить сложность создания фреймворка. Фреймворк должен позволят программисту явно описывать необходимые модели предметной области и прозрачно для программиста (неявно) расшаривать эти самые модели на всех узлах сети, где запущено данное приложение. Т.е я создал объект "автомобиль", задал его местоположение и скорость на одном узле и на остальных узлах эти данные появились без моего явного участия.
Я представляю это дело в виде фабрики, которая создает объекты заранее определенных классов и вся магия в этой фабрике заключается. С объектами работаю дальше как с обычными, без явных команд передать, засинхронизировать и т.д. Что посоветуете? Куда двигаться, что почитать.
PM MAIL   Вверх
xvr
Дата 14.1.2013, 13:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Немного похоже на DCOM. Можно с него и начать (в смысле ознакомления)

PM MAIL   Вверх
drug007
Дата 16.1.2013, 07:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



DCOM не подходит - слишком универсально. Я. правда, и не обрисовывал конкретную ситуацию. Область применения - сеть приложений, которые должны взаимодействовать друг с другом в различных сочетаниях. Например, есть узлы У1, У2 и У3 - узел У1 изменяет у себя величину В233, при этом У2 получает изменение величины В233, а У3 не заинтересован в ней и ему такие данные не нужны. Но он может быть заинтересован в других данных, которые не нужны У2. Т.е. связи между узлами довольно сложные, хотя формируются по простым алгоритмам - каждый узел избирательно подписывается на нужную ему информацию у всех нужных ему узлов. При этом все должно происходить прозрачно для программиста-пользователя фреймворка.
Лично у меня идея изобрести велосипед создать класс-фабрику, которая будет создавать базовый класс-контейнер плюс хранить в себе все данные в виде таблицы ключ-значение. Этот базовый класс-контейнер хранит в себе экземпляры другого базового класса-величины. Класс-величина преобразует свои значения в данные нижнего слоя - пары ключ-значение. Где ключом является номер узла, порядковый номер записи, идентификатор базового-класса контейнера и идентификатор базового класса-величины, а значением является собственно значение. А если в ключ добавить номер версии, то можно некоторое подобие персистентности организовать. 
Таким образом, возможно из пар ключ-значение данные вернуть в виде класса и класс преобразовать в пары ключ-значение. И смысл разделения на два слоя в том, что нижний слой - эти самые записи, можно передавать между узлами независимо от верхнего слоя. При чтении значения из экземпляра класса-величины происходит поиск по ключу и возврат значения. Конечно, тут издержки по времени и по памяти, но память сейчас дешевая, а скорость при необходимости можно увеличить за счет кэширования данных в критичном месте.
Да, еще в основе лежит утверждение, что каждый узел генерирует уникальную информацию, не пересекающуюся с другими узлами и не конфликтующую. Т,е. если мы имеем кучу складов, то каждый склад отвечает сам за себя. А если мы хотим отгрузить со склада находясь в офисе, то должны запрос отправить складу и только после обработки складом можем реально отгружать. Таким образом (имхо, конечно) избегаются лишние блокировки - они возникают, только когда несколько запросов к одному складу. Но это ограничение накладывается не программной моделью, а самой бизнес-моделью - если поставить на один склад несколько кладовщиков и они не будут согласовывать между собой свои действия, то ничего хорошего из этого не выйдет.
Покритикуйте, пожалуйста.

Это сообщение отредактировал(а) drug007 - 16.1.2013, 07:09
PM MAIL   Вверх
xvr
Дата 16.1.2013, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Задача понятна, но вы подходите к ее решению не с той стороны  smile Сначала определитесь как будут взаимодействовать узлы в сети. В частности как будет происходить исследование топологии сети - какие узлы в ней есть и какие значения есть у каждого узла. Должна ли быть топология динамической (что делать при добавлении новых узлов и при исчезновении старых)?

Цитата(drug007 @  16.1.2013,  07:04 Найти цитируемый пост)
Лично у меня идея изобрести велосипед создать класс-фабрику, которая будет создавать базовый класс-контейнер плюс хранить в себе все данные в виде таблицы ключ-значение.

На мой взгляд несколько усложнено. Какие типы значений предполагаются?

В любом случае, прежде чем проектировать реализацию, разработайте интерфейс пользовательского уровня (в вашем случае - уровня программиста, пользователя вашего фреймворка)

PM MAIL   Вверх
drug007
Дата 16.1.2013, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



Цитата(xvr @  16.1.2013,  13:43 Найти цитируемый пост)
 любом случае, прежде чем проектировать реализацию, разработайте интерфейс пользовательского уровня (в вашем случае - уровня программиста, пользователя вашего фреймворка)

А интерфейса как такового и нет. В этом то и смысл фреймворка. Т.е. если я создаю класс
Код

class A {
    int Foo;
    float Bar;
}

я максимум что делаю, объявляю мемберы через шаблон и делаю скрытым конструктор (у меня же фабрика):
Код

class A {
private:

    MyFactoryClass _mfc;

    A(MyFactoryClass mfc) {
        _mfc = mfc;
    ...
    }
public:
    Value<int> Foo;
    Value<float> Bar;
}


Ну возможно еще геттеры/сеттеры. Вот и весь интерфейс. Все остальное должно обрабатываться автомагически в классе-фабрике. Топология сети динамическая, на первом этапе информация тупо дублируется между всеми узлами, позже добавлю управление обменом. Так как выделено два слоя, то отработкой взаимодействия на сетевом уровне можно заниматься независимо от уровня интерфейса, что одна из целей.
Discovery service я планирую решать позднее, ибо вещь нужная, но независимая. 
Определить у кого какая информация можно на основе того, что каждый узел генерирует уникальную информацию в масштабах всей системы (это важное условие в основе моего подхода - возможно ошибочное, что и хочу обсудить), то узлы легко могут оповестить друг друга о том, какой информацией они обладают - тупо по своему номеру (узла) и идентификатору последнего сообщения.
Типы значений пока предполагаю только POD. Но не вижу проблем позднее добавить поддержку указателей и классов. В конце концов можно взять библиотеку сериализации - тогда можно будет использовать все типы, поддерживаемые библиотекой, но здесь нужно на практике проверить.

Это сообщение отредактировал(а) drug007 - 16.1.2013, 14:03
PM MAIL   Вверх
xvr
Дата 16.1.2013, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(drug007 @  16.1.2013,  13:55 Найти цитируемый пост)
Вот и весь интерфейс. 

Вполне нормальный интерфейс, но явно не полный. У вас в интерфейсе должно быть определено, как разделяются инстансы классов, а не их типы (т.е. не class A, а A my_class_a)
Вот у инстансов и должны быть какие то идентификаторы, что бы их можно было опознать из других узлов сети.
Далее, как узлы сети должны получать разделенные объекты из других узлов? Это не могут быть те же инстансы классов, что и их собственные объекты - т.е. нужно их как то отдельно именовать

Цитата(drug007 @  16.1.2013,  13:55 Найти цитируемый пост)
А интерфейса как такового и нет.

Пока нет, а должен быть  smile 

Цитата(drug007 @  16.1.2013,  13:55 Найти цитируемый пост)
Discovery service я планирую решать позднее, ибо вещь нужная, но независимая. 

Это не так - вполне зависимая. 
Цитата(drug007 @  16.1.2013,  13:55 Найти цитируемый пост)
Определить у кого какая информация можно на основе того, что каждый узел генерирует уникальную информацию в масштабах всей системы (это важное условие в основе моего подхода - возможно ошибочное, что и хочу обсудить), то узлы легко могут оповестить друг друга о том, какой информацией они обладают - тупо по своему номеру (узла) и идентификатору последнего сообщения.

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

PM MAIL   Вверх
drug007
Дата 16.1.2013, 20:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



Цитата(xvr @  16.1.2013,  14:54 Найти цитируемый пост)
Вполне нормальный интерфейс, но явно не полный. У вас в интерфейсе должно быть определено, как разделяются инстансы классов, а не их типы (т.е. не class A, а A my_class_a)
Вот у инстансов и должны быть какие то идентификаторы, что бы их можно было опознать из других узлов сети.
Далее, как узлы сети должны получать разделенные объекты из других узлов? Это не могут быть те же инстансы классов, что и их собственные объекты - т.е. нужно их как то отдельно именовать

Я это представляю через константы:
Код

class ValueContainer;

struct KeyValuePair<T, U>{
    T key;
    U value;
}

class MyFactory {
private:
    int _node_id;
...

public:

    MyFactory(int node_id) {
        _node_id = node_id;
    }

    ValueContainer* makeValueContainer() {
        return new ValueContainer(this);
    }

    void putData(KeyValuePair* kvpair);
    
    KeyValuePair<T, U>* getData(T key);
}

class ValueContainer {
private:
    friend MyFactory; 

    MyFactory* _myfactory; // parent
    const int _id = "some fixed unique value"; // own id
    ValueContainer(int myfactory) {
        _myfactory= myfactory;
    }

public:
    Value<T>* makeValue<T>() {
        return new Value<T>(this);
    }
}

template<T>
class Value {
private:
    T _value;
    ValueContainer* _valcont;
    const int _id = "some fixed unique value";

    Value(ValueContainer* valcont) {
        _valcont = valcont;
    }
public:
    void set(T value) {
        KeyValuePair kvpair;
        kvpair.key = ... make our key from _myfactory._node_id, _valcont._id, _id - for example like array of 3 int.
        kvpair.value = value;
        _valcont._myfactory.putData(kvpair);
    }
    U get(T key) {         
        return _valcont._myfactory.getData(key).value;
    }
    
}

Т.е. фабрика имеет уникальный ид, контейнер имеет уникальный внутри фабрики ид и величина имеет уникальный ид внутри контейнера  - втроем они составляют уникальный ид в масштабах всей системы. Фабрика(на самом деле получается не фабрика, а хранилище - так правильнее, создает динамически контейнеры через вызов makeContainer, а контейнеры внутри себя создают величины напрямую. Потом идет работа с величинами, а их изменения обрабатываются хранилищем. Взять какое-нить бинарное дерево для этого, хранить пары ключ-значение упорядоченно - т.е. добавить еще один ключ из номера хранилища и порядкового номера пары, а пару ключ-значение использовать как значение. И чтобы синхронизироваться, нужно просто обменяться данными - для какого хранилища какая последняя пара хранится. Отсюда можно легко определить какие данные куда нужно передать и делать это можно в другом потоке. Как думаете?
код не компилил, не обессудьте smile
Цитата(xvr @  16.1.2013,  14:54 Найти цитируемый пост)
Это не так - вполне зависимая. 

Я имею в виду, что вполне можно позднее ее реализовать, нет? Меня, в приниципе устроит и фиксированная топология сети, но динамическая это конечно другой уровень...

Цитата(xvr @  16.1.2013,  14:54 Найти цитируемый пост)
Оповестить мало - что бы другой узел смог воспользоваться этой информацией, он должен о ней знать заранее (если фреймворк будет работать на этапе компиляции), либо скатываться в чистую динамику и интерпретацию информации о типах в runtime.

А я только про динамику и думаю. Честно говоря не знаю, как это можно в компайл-тайм сделать. Расскажите подробнее, пожалуйста.


Это сообщение отредактировал(а) drug007 - 16.1.2013, 20:42
PM MAIL   Вверх
xvr
Дата 17.1.2013, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(drug007 @  16.1.2013,  20:32 Найти цитируемый пост)
втроем они составляют уникальный ид в масштабах всей системы.

А как другие узлы узнают, какой именно 'уникальный ID' им нужен и с какого узла его брать?

Цитата(drug007 @  16.1.2013,  20:32 Найти цитируемый пост)
А я только про динамику и думаю.

Динамика в данном контексте обозначает, что данные могут быть не только числа, а вообще любые. И их потребитель будет разбираться в рантайме с тем, что ему пришло. Это не самый удачный выбор  smile 

Могут ли на узле в процессе работы программы появляться новые типы данных (и запрашиваться с других узлов новые типы)? Если нет, то обычная статическая инициализация вполне подойдет.

Конкретное данное обозначается строкой (все строки в составе сети уникальны), и статическим экземпляром класса. Как то так -

Код

// On global level. Outside any function/member/class

SharedVar<int> my_var("node1.val1"); // Shared var (i'm a producer)
SharedVarRO<std::string> imported_var("node2.val2"); // Imported var from somewhere

// Using
void func()
{
  int i=my_var;
  my_var=10;
  std::string s=imported_var;
}

Устроит?

PM MAIL   Вверх
drug007
Дата 17.1.2013, 16:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



Цитата(xvr @  17.1.2013,  12:32 Найти цитируемый пост)
А как другие узлы узнают, какой именно 'уникальный ID' им нужен и с какого узла его брать?

Номер узла они получают при конфигурации системы - либо из конфигурационного файла, либо от discovery service. Номера контейнера и величин определяется статически в компайл-тайм - т.е. узел знает, информация каких контейнеров и какие величины ему нужны. Если контейнер инкапсюлирует склад, то узел-офис, знающий про этот склад, знает, что ему интересно на данном складе и какие id эти позиции имеют. Если вдруг появится новая какая-то величина, id которой неизвестен узлу, то она будет отображаться как неизвестная величина, т.е. это будет ошибкой бизнес-логики, но не приложения.
Цитата(xvr @  17.1.2013,  12:32 Найти цитируемый пост)
Могут ли на узле в процессе работы программы появляться новые типы данных (и запрашиваться с других узлов новые типы)? Если нет, то обычная статическая инициализация вполне подойдет.

Новые типы данных появляться могут, но с ограничениями - чтобы появление таких типов не разрушало работоспособность системы. Т.е. например мы собрали новый билд и в нем новый тип - старые билды не должны падать общаясь с новым, а только лишь фиксировать факт получения данных, которые они не могут классифицировать. Я это вижу как складывание таких данных отдельно от остальных без выдачи фатальной ошибки, но с извещением оператора, ну и логом.
Цитата(xvr @  17.1.2013,  12:32 Найти цитируемый пост)
код C++
Код

// On global level. Outside any function/member/class
SharedVar<int> my_var("node1.val1"); // Shared var (i'm a producer)
SharedVarRO<std::string> imported_var("node2.val2"); // Imported var from somewhere
// Using
void func()
{
  int i=my_var;
  my_var=10;
  std::string s=imported_var;
}


Устроит?

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

class Container {
    SharedValue<..> shared_val1;
...
    SharedValue<..> shared_valN;

   void process();
}

class Storage {
  Container* _containers[];
...
public:
   Container* getContainer(int cont_id);
}


Storage* store = new Storage("config.ini");  // this is single place where data-sharing subsystem is used directly in some way

SharedVar<int>* my_var = store.make<SharedVar<int> >(); // Shared var (i'm a producer) all prorammer needed know to share data is Storage
// now my_var is automagically published to other nodes listed in configuration file from Strorage ctor.

SharedVarRO<std::string>* imported_var = store.make<SharedVar<std::string> >("node2", "val2"); // Imported var from somewhere
// thanks for hint - I should develop read-only values also

// Using
void func()
{
  int i=my_var;
  my_var=10;
  std::string s=imported_var;

  // the second way to import value
   auto cont = (cast to derivative class if needed) storage.getContainer(2); //container id may be run-time value. but casting isn't good thing...
   auto imported_var = cont->val2(); // value name is compile-time
   if(imported_var)
       doSomething(imported_var);
}

Как-то так...

Это сообщение отредактировал(а) drug007 - 17.1.2013, 16:59
PM MAIL   Вверх
xvr
Дата 17.1.2013, 21:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(drug007 @  17.1.2013,  16:54 Найти цитируемый пост)
Новые типы данных появляться могут, но с ограничениями - чтобы появление таких типов не разрушало работоспособность системы

Я имел в виду не типы, а экземпляры

Цитата(drug007 @  17.1.2013,  16:54 Найти цитируемый пост)
Т.е. он пишет код как для обычного приложения, не распределенного. Проблему кто с кем взаимодействует должен решать администратор приложения путем конфигурации.

Согласен.

Немного по поводу кода - я бы не стал генерить классы через new. Все же С++ это не Java, в нем можно экземпляры классов делать и не на куче, даже лучше делать не на куче.
Далее, все манипуляции с контейнером и конфигурацией лучше оставить внутри фреймворка - програмисту о них знать не имеет смысла. 

Связывать переменные SharedVar[RO] можно по их строковым именам, не привязываясь ни к каким конфиг файлам, при этом все равно где именно они находятся.
В принципе SharedVar может быть сделан не только от int и string, но и от любого класса, поддерживающего стриминг (определенный набор методов)

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

PM MAIL   Вверх
drug007
Дата 18.1.2013, 10:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



Цитата(xvr @  17.1.2013,  21:53 Найти цитируемый пост)
Я имел в виду не типы, а экземпляры

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

Цитата(xvr @  17.1.2013,  21:53 Найти цитируемый пост)
Немного по поводу кода - я бы не стал генерить классы через new. Все же С++ это не Java, в нем можно экземпляры классов делать и не на куче, даже лучше делать не на куче.

Имеете в виду кастомный аллокатор? Или стек?
Цитата(xvr @  17.1.2013,  21:53 Найти цитируемый пост)
Далее, все манипуляции с контейнером и конфигурацией лучше оставить внутри фреймворка - програмисту о них знать не имеет смысла. 

Согласен, я на черновую просто написал для примера.
Цитата(xvr @  17.1.2013,  21:53 Найти цитируемый пост)
В принципе SharedVar может быть сделан не только от int и string, но и от любого класса, поддерживающего стриминг (определенный набор методов)

Точно так, правда пока хочу ограничиться pod-типами - без указателей и ссылок.
Цитата(xvr @  17.1.2013,  21:53 Найти цитируемый пост)
Если такая функциональность и интерфейсы устраивают, то можно переходить к проработке реализации.

Вы были абсолютно правы про интерфейс - я подумал как будет работать пользователь и пришел к выводу, что без персистентности не получится адекватной работы. Смысл в том, что обмен данными между узлами асинхронный (синхронность предъявит жесткие требования к аппаратной части). А значит, возможна ситуация, когда на разных узлах разные данные и решить эту проблему можно путем версий значения - т.е. если узлу нужно произвести какие-то расчеты, для расчетов нужно, например, 3 величины. Он берет их значения, находит их время обновления, выбирает величину с наименьшим, а по остальным величинам еще раз запрашивает значения, но уже с наименьшим временем и на основании этих данных производит расчет и ему присваивает это же самое время. А это означает, что нужно продумать еще алгоритм. Правда, получается, что часть проблем я все-таки выношу из фреймворка и программист уже должен будет учитывать время обновления значения величины, но думаю, это оправдано будет в данном случае, как думаете?
С эфемерными величина проще конечно было бы написать реализацию, но как тогда решить проблему рассинхронизации?

Цитата(xvr @  16.1.2013,  14:54 Найти цитируемый пост)
Оповестить мало - что бы другой узел смог воспользоваться этой информацией, он должен о ней знать заранее (если фреймворк будет работать на этапе компиляции), либо скатываться в чистую динамику и интерпретацию информации о типах в runtime.

Я первоначально неправильно понял вопрос - да, фреймворк будет работать на этапе компиляции. Чистая динамика слишком уж усложнит реализацию, по крайней мере пока можно без нее обойтись.
PM MAIL   Вверх
xvr
Дата 18.1.2013, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(drug007 @  18.1.2013,  10:13 Найти цитируемый пост)
но будут массивы таких величин

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

Цитата(drug007 @  18.1.2013,  10:13 Найти цитируемый пост)
Имеете в виду кастомный аллокатор? Или стек?

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

Цитата(drug007 @  18.1.2013,  10:13 Найти цитируемый пост)
А значит, возможна ситуация, когда на разных узлах разные данные и решить эту проблему можно путем версий значения - т.е. если узлу нужно произвести какие-то расчеты, для расчетов нужно, например, 3 величины. Он берет их значения, находит их время обновления, выбирает величину с наименьшим, а по остальным величинам еще раз запрашивает значения, но уже с наименьшим временем и на основании этих данных производит расчет и ему присваивает это же самое время.

Это требует наличие синхронизированного времени на всех узлах (например в виде NTP клиента), что в свою очередь требует единого сервера для задания этого самого времени.

Лучше сделать так, что бы на узлах всегда присутствовали самые последние версии значений. Это можно обеспечить просто сделав взаимодействие узлов в push режиме - узел, поменявший свою переменную, немедленно рассылает ее всем заинтересованным сторонам  smile 

Цитата(drug007 @  18.1.2013,  10:13 Найти цитируемый пост)
Правда, получается, что часть проблем я все-таки выношу из фреймворка и программист уже должен будет учитывать время обновления значения величины, но думаю, это оправдано будет в данном случае, как думаете?

Я думаю, что проблема тут сложнее, чем кажется. Что считать синхронизацией значений, если учитывать то, что эти значения вырабатываются асинхронно работающими узлами? Для того, что бы вообще говорить о 'синхронизации' в любом понимании нужно иметь точку отсчета, одинаковую на всех узлах. И узлы должны знать об этом и учитывать в своей работе. Синхронизация по времени в принципе не самая удачная методика.

Зачем вообще нужна синхронизация?

PM MAIL   Вверх
drug007
Дата 18.1.2013, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1




Цитата(xvr @  18.1.2013,  11:58 Найти цитируемый пост)
Это можно учесть, введя тип разделяемой переменной - массив. Тогда новых переменных в процессе работы программы появляться не будет

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

Цитата(xvr @  18.1.2013,  11:58 Найти цитируемый пост)
Я имею в виду обычные глобальные статические переменные.

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

Цитата(xvr @  18.1.2013,  11:58 Найти цитируемый пост)
Лучше сделать так, что бы на узлах всегда присутствовали самые последние версии значений. Это можно обеспечить просто сделав взаимодействие узлов в push режиме - узел, поменявший свою переменную, немедленно рассылает ее всем заинтересованным сторонам

Совершенно верно. Но я боюсь, что может получится такая ситуация - узел У1 изменил переменную П1, узел У2 изменил переменную П2, а узел У3 начал какие-то вычисления (запустил отчет, например) на основе переменной У1.П1 и У2.П2, но при этом от узла У1 пришло новое значение, а от У2 еще не успело - т.е. получится наполовину правильные расчеты. Можно поставить дело так, что У3 получив новое значение У2 заново выполняет отчет и тогда все становится действительно актуальным. И моя мысль сделать это как бы более явным с помощью временной метки - тогда узел У3 просто бы пометил свои расчеты меткой самых молодых данных. Но пишу и чувствую, как все усложняется резко с этими метками...  smile  Про метки я подумал еще в связи с тем, что ряд данных в приложении должны регулярно записываться в лог с такой временной меткой - вот я и подумал про метки, но чувствую, что не то это...

Цитата(xvr @  18.1.2013,  11:58 Найти цитируемый пост)
Зачем вообще нужна синхронизация?

Неправильно я использовал термин синхронизация, правильнее актуализация - т.е. получение последнего значения.
PM MAIL   Вверх
xvr
Дата 18.1.2013, 15:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(drug007 @  18.1.2013,  12:37 Найти цитируемый пост)
Это учитывает, что разделяемая переменная является массивом. А я имею в виду массив разделяемых переменных - т.е. мы на этапе компиляции будем иметь тип переменной, а их количество узнаем в рантайме.

Это все равно будет массив, но динамический. Его размер может изменяться в рантайме (вместе со значением элементов)

Цитата(drug007 @  18.1.2013,  12:37 Найти цитируемый пост)
Но я боюсь, что может получится такая ситуация - узел У1 изменил переменную П1, узел У2 изменил переменную П2, а узел У3 начал какие-то вычисления (запустил отчет, например) на основе переменной У1.П1 и У2.П2, но при этом от узла У1 пришло новое значение, а от У2 еще не успело - т.е. получится наполовину правильные расчеты.

С учетом того, что узлы работают асинхронно, вполне законным будет любой порядок вычислений: старое значение П1+новое значение П2, или новое значение П1+старое П2, или оба старых или оба новых. 

Например - 2 узла вырабатывают новые значения 2х переменных каждую миллисекунду, со сдвигом в 0.5ms. Когда брать 'новое' значение с обоих узлов?

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

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

PM MAIL   Вверх
drug007
Дата 18.1.2013, 17:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 196
Регистрация: 3.11.2011

Репутация: нет
Всего: 1



Цитата(xvr @  18.1.2013,  15:48 Найти цитируемый пост)
Это все равно будет массив, но динамический. Его размер может изменяться в рантайме (вместе со значением элементов)

я все-таки разделяю эти два момента:
SharedVar<int> sv_arr1[10];
SharedVar<int[10]> sv_arr2;
Ведь в первом случае мы можем индивидуально менять значение каждого элемента массива. А во-втором случае мы будем менять весь массив сразу. В принципе результат будет один и тот же, но первый вариант оптимален когда мы часто меняем элементы массива по одному, а второй когда меняем весь массив сразу.

Цитата(xvr @  18.1.2013,  15:48 Найти цитируемый пост)
Например - 2 узла вырабатывают новые значения 2х переменных каждую миллисекунду, со сдвигом в 0.5ms. Когда брать 'новое' значение с обоих узлов?

В этом случае по идее можно и пренебречь разницей во времени, так как разница будет небольшой, даже если одно значение придет с опозданием, то ошибка будет в 0.5 мс. А вот если один узел так же быстро вырабатывает значения, а второй раз в 1 секунду и со второго узла одно значение придет с опозданием, то ошибка составит целую секунду и может быть критической. Вообще у меня впечатление, что это проблема не фреймворка должна быть, а его пользователя, так как нужно знать подробности приложения. Однако какие-то средства на этот случай во фреймворке должны быть, наверное?
Цитата(xvr @  18.1.2013,  15:48 Найти цитируемый пост)
Вот только синхронизация тут нужна хитрая, обычные мьютексы и семафоры не подойдут, да и на метках времени синхронизацию тоже не построишь  

Тут я думаю синхронизация как внутри процесса будет гиблым делом. Слишком разные среды. Я думаю, что эти вопросы надо выносить на уровень пользователя библиотеки, пусть у него голова болит. Т.о. нужно предоставить программисту возможность самостоятельно определять какие данные актуальны - т.е. если ему нужно определить актуальность данных пусть делает сам. Нужно какую-то метку ставить - пусть сам ставит. А задача фреймворка только расшаривать данные. Как думаете?

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1041 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.