Страницы

Поиск по вопросам

понедельник, 3 декабря 2018 г.

Angular 2 thinking and way

Ситуация: Есть два очень похожих компонента: превью статьи на главной странице, и сама статья, при переходе на "читать дальше". У компонента превью свой сервис, который тянет данные через http. В роутере, при переходе на полноую статью (другой компонент) указан компонент статьи, непосредственно.
Вопрос: Создавать копмоненту свой собственный сервис, который будет дублировать код сервиса превьюхи, либо же использовать один компонент, просто с отдельным шаблоном целой статьи (//не нашел, как юзать несколько шаблонов в одном компоненте), либо же ваш вариант. Интересует именно правильный подход с точки зрения angular way и TS. Заранее благодарю.


Ответ

Для обоих компонентов можно сделать через один сервис

Как узнать из главного потока, что побочный поток завершился ошибкой?

Есть главный поток(1) и из него вызывается побочный поток(2)
Выглядит примерно так:
Thread second_thread = new Thread(null, new Runnable() { public void run() { throws new Exception(); } }); second_thread.start(); second_thread.join();
Как узнать из главного потока, что побочный поток завершился ошибкой?


Ответ

Классы Callable и Future как раз созданы чтобы решить эту проблему. Вопрос разрешен.

Не работает блокировка для большого количества запросов

Здравствуйте. Дело в том, что я использую сокеты. И почти в одно и то же время, допустим, в 20 часов и 0 минут, у всех пользователей скрипт отправляет запрос на сокет сервер. Отправляя этот запрос, у меня есть цель: выполнить нужное мне событие (1.1) один раз, и вернуть всем результаты. Но у меня не совсем получается.
Я делаю так: когда приходит запрос от пользователя я проверяю, был ли запрос раньше, и если не было, помечаю в базе, что запрос только что произошел. Дальше, если еще кто-то шлет запрос, то уже видно, что запрос уже произошел, и текущий клиент ждет выполнения нужного мне события (1.1). Проблема состоит в том, что иногда Node.JS не успевает выполнить запрос к базе, и за это время, пока идёт запрос, успевает "проскочить" несколько клиентов и нужно мне события (1.1) выполняется столько раз, сколько пользователей проскочило, плюс тот пользователь, что инициировал первый запрос.
Как быть? Может есть какой-то алгоритм? Уже голову сломал.


Ответ

Как вариант, можно использовать именнованые локи MySQL
SELECT GET_LOCK('lock_name', 60);
Документация

Вызов шаблонной функции через Qtconcurrent::run

Есть шаблонная функция:
template auto exceptionWrapper (Object *obj, Function&& function, Args&& ...args)-> decltype((obj->*function)(std::forward(args)...)) { try { QScopedPointer tempObj(new Object(obj->getSomeData())); return (tempObj->*function)(std::forward(args)...); } catch(std::exception& e) { ... } }
Есть другая функция, которая ее вызывает через qtConcurrent::run
template void Object::callAsync(Object *obj,Function&& query,CallBack&& callBack, Args&& ...args) {
using ReturnValue = decltype(exceptionWrapper(obj, query, std::forward(args)...)); QFutureWatcher watcher; connect(&watcher, &QFutureWatcher ::finished, callBack); QFuture futureValue = QtConcurrent::run(exceptionWrapper, obj, query, std::forward(args)...);
watcher.setFuture(futureValue); }
При попытке вызова в коде:
Object object = new Object(); Object::callAsync(object, Object::objFcn, [](){qDebug()<<"qq";}, arg1, arg2);
Возникает ошибка:
ошибка: no matching function for call to 'run(, BOKZDatabase*&, AngleOrientData (BOKZDatabase::*&)(const QString&, const QString&, const QString&, const QString&, int), const QString&, const QString&, const QString&, const QString&, const int&)' QFuture futureValue = QtConcurrent::run(exceptionWrapper, db, query, std::forward(args)...); ^
Что я упустил?
UPD: В случае явного указания параметров шаблона ошибка о неопределенном типе функции остается:
template void Object::callAsync (Object *obj,Function&& query,CallBack&& callBack, Args&& ...args) {
using ReturnValue = decltype(exceptionWrapper(obj, query, args...)); QFutureWatcher watcher; connect(&watcher, &QFutureWatcher ::finished, callBack); QFuture futureValue = QtConcurrent::run(exceptionWrapper , obj, std::forward(query), std::forward(args)...); watcher.setFuture(futureValue); }
UPD 2. Минимальный пример:
class Object { public: int sum(int a, int b) { return a+b; } };
template auto fcn (Object *object, Function&& function, Args&& ...args)-> decltype ((object->*function)(std::forward(args)...)) { return (object->*function)(std::forward(args)...); }
template void callAsync(Object *object,Function&& function, Args&& ...args) {
QtConcurrent::run(fcn >, object, function, std::forward(args)...);
}
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Object* obj = new Object();
callAsync(obj, Object::sum, 5, 6); return a.exec(); }


Ответ

exceptionWrapper сам по себе не является функцией, но неким шаблоном функции, поэтому мы не можем никуда его передать — мы можем передавать лишь что-то конкретное, а не абстракцию, коей является шаблон.
Таким образом, нам нужно конкретизировать (инстанциировать) exceptionWrapper прежде чем передавать его в QtConcurrent::run. Здесь встаёт другая проблема: с какими аргументами инстанциировать? Т.к. exceptionWrapper использует пробрасывающую ссылку (forwarding reference), идёт расчёт на то, что аргументы будут выводиться при вызове функции, но у нас ситуация иная — мы явно задаём аргументы шаблона. Конечно, мы всё равно получаем нужный результат таким вызовом:
QtConcurrent::run(exceptionWrapper, obj, std::forward(query), std::forward(args)...);
Происходит это из-за того, что у нас в callAsync пробрасывающая ссылка, а в exceptionWrapper, в результате явной инстанциации, у нас rvalue-ссылка, и применяя правила C++ по свертке ссылок мы на выходе имеем то, что и ожидали: будет инстанциирована правильная, т.е. ожидаемая нами функция exceptionWrapper. К примеру, если мы рассмотрим минимальный пример, из Вашего дополненного вопроса, то при таком вызове:
int var = 5; callAsync(obj, &Object::sum, 7, var);
Будет сгенерирована функция exceptionWrapper с такой сигнатурой: int (Object *,int (Object::* )(int,int),int &&,int &) — как раз то, что и ожидалось. Но в этом кроется другая проблема. Мы работаем с конкурентной средой и пытаемся вызвать метод Qt, который потенциально выполнит наш метод в другом потоке. Но, чтобы выполнить метод в другом потоке, он вынужден скопировать (либо же переместить, если умеет) аргументы и сохранить их до того времени, когда можно будет вызвать нашу функцию.
Сохраняя наши аргументы, Qt отбрасывает их изначальный тип и впоследствии, при передаче их в нашу функцию, все наши аргументы станут lvalue. Но в сигнатуре нашей функции есть int&&, который является rvalue-ссылкой и lvalue не может быть передано туда! Поэтому, нам придётся отказаться от пробрасывающих ссылок в exceptionWrapper — они там не нужны и только мешают, там нужен обычный const &
В результате получим такое решение:
template auto fcn(Object *object, Function function, const Args& ...args) { return (object->*function)(args...); }
template void callAsync(Object *object, Function&& function, Args&& ...args) { QtConcurrent::run(fcn, object, function, std::forward(args)...); }
Конечно, можно подумать и над альтернативными решениями, но этот ответ уже и так довольно длинный получился.

Нужна критика по архитектуре классов в С++ для реализации таблиц ModBus

Изучаю С++ и пишу библиотеку ModBus. Прошу полезного совета у Гуру по изменению архитектуры в целом или ответить на конкретные вопросы в конце.
Я хочу с помощью шаблонов классов автоматически помещать любые пользовательские данные в нужные таблицы данных ModBus с возвращением указателей на них.
class AlarmData_b01 { bool isAlarm; bool isCountActivate; };
class MeintenanceData_b01 { bool isMeintenance; bool isCountActivate; };
class MeintenanceData_f32 { unsigned short Id; unsigned long Time; float Rate; };
AlarmData_b01 *AlarmData_b01_Alarm1_ptr = InputBits::Add(); AlarmData_b01 *AlarmData_b01_Alarm2_ptr = InputBits::Add();
MeintenanceData_b01 *AlarmData_b01_Meintenance1_ptr = InputBits::Add(); MeintenanceData_b01 *AlarmData_b01_Meintenance2_ptr = InputBits::Add();
MeintenanceData_f32 *AlarmData_f32_Meintenance1_ptr = InputRegs::Add(); MeintenanceData_f32 *AlarmData_f32_Meintenance2_ptr = InputRegs::Add();
Таким образом, для класса AlarmData создается свой класс, регистрирующий все объекты типа AlarmData. Тоже происходит и для класса MeintenanceData. Дискретные данные для аварий помещаются в таблицу дискретных данных, а данные 16 бит помещаются в таблицу регистров модбас.
Так же с помощью статического метода шаблонного класса можно задать адрес для созданной области объектов в таблице ModBus.
InputBits::AddresSet(100); InputBits::AddresSet(110);
InputRegs::AddresSet(100);
Таким образом будут формироваться таблицы данных, доступ к которым будет осуществляться из вне сторонним устройством по интерфейсу RS485 и протоколу ModBus с заданием адреса внутри посылки, указанного в моей программе с помощью AddresSet.
В начале мной был создан базовый шаблон класса
template class ModBusTables { protected:
static unsigned short Addres; static unsigned short AreaSize; T_DataType *AreaData_ptr;
ModBusTables();
public:
static void AddresSet(unsigned short ModBusAddres); };
где
static unsigned short Addres - Адрес области в таблице протокола Модбас static unsigned short AreaSize - Размер объектов в области T_DataType *AreaData_ptr - Тип для приведения указателя.
Так как в ModBus фактически существует только два типа данных: дискретные и ячейки по 16 бит, то в параметрах данного шаблона будет либо bool либо unsigned short. Таким образом AreaData_ptr - это указатель на тип данных конкретной таблицы ModBus, чтобы можно было путешествовать по любым данным пользователя с помощью единого указателя.
Теперь приведу код шаблонного класса, который наследуется от одного из классов выше и расскажу в чем заключается вопрос.
template class ModBusTable;
template class TT_Table> class ModBusTable > : public TT_Table { private:
T_DataStruct AreaData;
public:
static T_DataStruct *Add() { ModBusTable *ModBusArea_ptr = new ModBusTable();
T_DataStruct *Instance_Ptr = &ModBusArea_ptr->AreaData;
ModBusTable >::AreaSize = sizeof(ModBusArea_ptr->AreaData); ModBusArea_ptr->AreaData_ptr = (T_DataType *)Instance_Ptr;
return Instance_Ptr; } };
Главная задача данного шаблонного класса - создать свой объект в статическом методе, зарегистрировать его в классе и возвратить указатель на данные пользовательского типа, а так же преобразовать этот указатель в указатель AreaData_ptr объявленный в родительском классе, чтобы с любыми пользовательскими типами можно было работать через указатель на bool или unsigned short.
Теперь сам вопрос. Для того, чтобы не вбивать много параметров в шаблон для регистрирования пользовательских данных в конкретной таблице ModBus, я применил наследование.
template class InputBits: public ModBusTable > {}; template class InputRegs: public ModBusTable > {}; template class OutputBits: public ModBusTable > {}; template class OutputRegs: public ModBusTable > {};
Как логически объединить объекты классов
InputBits и InputBits?
Объекты этих классов логически должны находится в одной таблице ModBus.
Существует ли способ заменить наследование в данном случае на что-то похожее на alias template в С++11, чтобы создавать шаблон класса с новым именем InputBits по шаблону ModBusTable? Так, чтобы работало выражение
InputBits::Add()
Приму любые советы по изменению архитектуры реализации данной задачи. Большое спасибо за прочтение, внимание и ответы!


Ответ

Для стандарта C++11 и новее можно было бы записать
template struct Base{};
template using WrapperFirst = Base;
template using WrapperSecond = Base;
int main() { WrapperFirst a; WrapperSecond b;
return 0; }
Полного аналога alias template в C++03 построить не получится.
Можно использовать шаблон структуры для частичного задания параметров базового шаблона.
template struct Base{};
template struct Wrapper { typedef Base first; typedef Base second; };
int main() { Wrapper::first a; Wrapper::second b;
return 0; }

Html. Нарисовать линию

Нужно нарисовать или любым иным способом провести линию от одного блока div к другому. Т.е. два элемента связать линией. Элементы генерируются динамически.
Строится все это дело на основе уровней. Например, есть пользователь с уровнем 1. Он будет на самом верху. Дальше пользователи с уровнем 2, они ниже. Нужно их соединить любым способом, как на схеме. Схематичный пример:


Ответ

Например так:
var first = document.getElementById('first'); var second = document.getElementById('second'); var line = document.getElementById('line').getElementsByTagName('line')[0]; function shuffle() { var pos = { ft: Math.round(Math.random() * 50), fl: Math.round(Math.random() * 50), st: Math.round(Math.random() * 100) + 100, sl: Math.round(Math.random() * 100) + 200 } first.style.top = pos.ft + 'px'; first.style.left = pos.fl + 'px'; second.style.top = pos.st + 'px'; second.style.left = pos.sl + 'px'; line.setAttribute('x1', pos.fl + first.offsetWidth); line.setAttribute('y1', pos.ft + first.offsetHeight); line.setAttribute('x2', pos.sl); line.setAttribute('y2', pos.st); } shuffle(); document.getElementById('shuffle').addEventListener('click', shuffle); div { position: absolute; border: 2px solid #000; width: 100px; height: 50px; } #line { position: absolute; top: 0; left: 0; width: 100%; height: 100%; stroke: #F00; stroke-width: 2px; z-index: -1; } #shuffle { position: absolute; top: 20px; left: 50%; }


Как запретить ввод переменной меньше/больше заданного интервала?

Как запретить ввод переменной меньше/больше заданного интервала? Например: Из динамического одмерного массива нужно удалить N элементов, начиная с номера K. Ввод размера массива, n элементов и k вводится с клавиатуры. Нужно чтобы n было не меньше и не больше size.
Подскажите только, где об этом прочитать или кусочек кода, пожалуйста.


Ответ

Возможная последовательность действий такая:
Пользователь вводит число num Проверяем число if (num ... Если число удовлетворяет проверке идём дальше, если нет возвращаемся к шагу 1.
Код, обеспечивающий сам ввод, может быть совершенно разным и будет зависеть от того с какой системой вы работаете, в консоли или GUI, используете ли какие-то специфические библиотеки типа ncurses и т.д.