Страницы

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

пятница, 21 декабря 2018 г.

Потокобезопасная обертка над объектом

Есть ли минусы, которые могут заставить не использовать подобные обертки. Также подскажите, есть ли уже что-то подобное в stl или boost. Вот накидал пример:
SafeRef:
#include #include #include
template class SafeRef { public:
SafeRef(std::mutex &mutex, RefType ref) : m_reference(ref), m_mutex(mutex) { m_mutex.lock(); } SafeRef(SafeRef &&other) : m_mutex(other.m_mutex), m_reference(other.m_referance) { }
RefType get() const { return m_reference; }
~SafeRef() { m_mutex.unlock(); } private: std::mutex &m_mutex; RefType m_reference; };
Тестовый код:
class SomeObj { public: SafeRef&> getVector() const { return SafeRef&>(m_mutex, m_vector); } void reserve(int n) { std::lock_guard(this->m_mutex); m_vector.reserve(n); } void addElement(int i) { std::lock_guard(this->m_mutex); m_vector.push_back(i); } private: mutable std::mutex m_mutex; std::vector m_vector; //Большой вектор, копирование очень затратно };
void write(SomeObj &obj) { obj.reserve(500); for (int i = 0; i < 500; i++) { obj.addElement(i); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } }
void read(const SomeObj &obj) { for (int i = 0; i < 5; i++) { std::this_thread::sleep_for(std::chrono::seconds(1)); auto v = obj.getVector(); std::cout << v.get().size() << std::endl; } }
int main() { SomeObj obj; std::thread thread1(&write, std::ref(obj)); std::thread thread2(&read, std::ref(obj)); thread2.join(); thread1.join();
return 0; }


Ответ

Проблема этого подхода в том, что потокобезопасность намного сложнее
Вы не можете просто так сделать объект потокобезопасным, защитив все операции мьютексом. К примеру, у вас есть обёртка над стеком, дававйте посмотрим тогда на код
SupposedlySafeStack s; // ... if (!s.is_empty()) s.pop();
Проблема здесь в том, что между выполнением if (!s.is_empty()) и s.pop(); стек вполне мог стать пустым.
Для хорошего потокобезопасного стека нужен другой набор операций. Например, атомарный bool try_pop(T&) и push_range(Iterator begin, Iterator end). Потокобезопасность нужно планировать на уровне внешнего интерфейса класса.
То же относится к доступу по индексу к std::vector и так далее. Поэтому обёртки, которые оборачивают все публичные функции, непригодны: они лишь создают ложное чувство безопасности!
А обёртка на целый объект уже существует, это std::lock_guard

Кроме того, обычно вам нужно сделать потокобезопасным не один объект, а группу объектов и их отношения между собой. Например, у вас есть очередь и стек, как в алгоритме сортировочной станции; нет смысла иметь отдельно защищённый стек и отдельно очередь, потому что при этом они могут рассогласоваться во время вашей операции! Например, если вы переносите все элементы из стека в очередь, то после удаления всех элементов из стека перед добавлением в очередь в стеке могут образоваться новые элементы, и инвариант вашего алгоритма нарушится.
Вам придётся заводить явный мьютекс, и защищать не объекты, а ваши операции с объектами

Как одним #define запретить вывод в консоль в Qt?

Существует ли какой-то #define для запрета вывода текста в консоль? Например, такого:
qDebug() << "ololo";
Почему-то текст выводится даже в релизной сборке.


Ответ

В файл проекта надо добавить строку
DEFINES += QT_NO_DEBUG_OUTPUT

Почему сайты не доступны по ip адресу?

Почему, если вбить в поисковую строку браузера ip-адрес сайта вместо url он будет не доступен? Если я не ошибаюсь, браузер не откроет сайт по ip-адресу, даже если у сайта ip выделенный.


Ответ

Это зависит от настроек сервера и вида веб-сервера. Обычно, если специально ничего не делать, и сайт только один на сервере, то он будет открываться и по IP адресу. Несложно сделать так, чтобы для неизвестных доменов, и для запросов без заголовка Host, откры­вался ка­кой-то специально предназначенный сайт с одной страницей с объяснениями.
Например, в случае nginx такой специальный сайт должен быть помечен параметром default_server
Если мы говорим о каком-то массовом виртуальном хостинге, то обычная практика делать имен­но так, то есть ограничивая доступ к серверу по IP. Никто не хочет выслушивать жалобы от недо­вольного клиента, сайт которого, по случаю оказавшийся первым в списке, откры­ва­ется при вво­де в адресную строку какого-то другого домена, который по любой причине ука­зывает на IP сервера. Владелец того другого домена тоже не будет рад такому развитию событий.
Если ваш сайт работает по HTTPS, то одной настройки сервера будет недостаточно. Нужно будет получить SSL сертификат и для домена, и для IP адреса. Последнее не всегда возможно.

Регулярка, только пробелы \s, исключая \n

Пытаюсь заменить в строке пробелы повторяющиеся два и более раза на одинарные, вот так:
$str=preg_replace("/\s{2,}/"," ",$str);
Но параметр \s заменяет не только пробелы, но и символы перевода строки
причем на пробел, а мне нужно только пробелы и табуляции. Как сделать?


Ответ

Вариант 1. Напишите символы явно - пробел и табуляцию
$str=preg_replace("/[ \t]{2,}/"," ",$str);
Вариант 2. Строку разделить на кусочки (split/exlode) по переводу строки. Каждую строку обработать и потом сделать join. Выглядит немного странно, но зато поможет решить проблему вида "у меня есть пробелы в начале и конце строки, как и их удалить?".

Как выводить рандомную строку?

Как выводить рандомную строку после остановки анимации, например? На данный момент у меня реализовано так:
@Override public void onAnimationEnd(Animation animation) { //вывод текст здесь String[] texts = {}; Set generated = new HashSet(); Random random = new Random (); int pos = random.nextInt(texts.length);
((TextView) findViewById(R.id.myTextView)).setText(texts[pos]); }
@Override public void onAnimationRepeat(Animation animation) {
} });
Но проблема в том, что значений в String[] texts = {раз, два, ......, тысяча}; больше тысячи это во первых, а во вторых хотелось бы хранить все в строках, так как в дальнейшем планируется локализация для разных языков.

@Override public void onAnimationEnd(Animation animation) { //вывод текст здесь
Resources res = getResources(); String[] planets = res.getStringArray(R.array.planets_array);
Set generated = new HashSet(); Random random = new Random (); int pos = random.nextInt(R.array.planets_array);
((TextView) findViewById(R.id.myTextView)).setText(planets[pos]);

}
@Override public void onAnimationRepeat(Animation animation) {
} });
}
}

CatLog выдает следующее:
-09 23:03:08.846 3579-3579/ru.infernal93.butilochka E/AndroidRuntime: FATAL EXCEPTION: main Process: ru.infernal93.butilochka, PID: 3579 java.lang.ArrayIndexOutOfBoundsException: length=4; index=2122146214 at ru.infernal93.butilochka.ActivityGame$2.onAnimationEnd(ActivityGame.java:81) at android.view.animation.Animation$3.run(Animation.java:376) at android.os.Handler.handleCallback(Handler.java:742) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:5527) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629) 10-09 23:03:08.848 3579-3579/ru.infernal93.butilochka E/MQSEventManagerDelegate: failed to get MQSService.


Ответ

В ресурсах можно хранить массивы
Mercury Venus Earth Mars

Resources res = getResources(); String[] planets = res.getStringArray(R.array.planets_array);

Ошибочная сериализация полей с Gson

У меня в обьекте есть поле:
@SerializedName("CommentPhotoes") @Expose(serialize = false) private ArrayList commentPhotos;
Мне это поле нужно распарсить когда я считываю этот объект из строки, но когда я его обратно сериализую в строку, это поле не должно туда попасть.
Проблема заключается в том что при сериализации объекта - это поле тоже сериализуется. При чем тоже самое касается и десериализации.
В чем может быть проблема, может я неправильно использую эти аннотации?


Ответ

По умолчанию наличие аннотации @Expose ни на что не влияет. Поэтому при создании объекта Gson с помощью GsonBuilder нужно явно указать, как обрабатывать эти аннотации.
Возможны варианты:
Помечать нужные поля этой аннотацией Помечать игнорируемые поля этой аннотацией Использовать модификатор transient вместо аннотаций
Подробнее:
Помечаем поля, которые хотим сериализовать/десериализовать аннотацией @Expose, при создании Gson объекта говорим, что поля без этой аннотации надо игнорировать:
Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create(); Помечаем поля, которые хотим игнорировать и в сериализации и в десериализации аннотацией @Expose, при создании Gson объекта добавляем ExclusionStrategies
Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { return f.getAnnotation(Exclude.class) != null; }
@Override public boolean shouldSkipClass(Class c) { return false; } }) .create();
Чтобы исключить поля только в сериализации или только в десериализации нужно добавлять аннотацию @Expose с параметром serialize=false или deserialize=false
class Book { // игнорируется только при сериализации @Expose(serialize = false) String field1; // игнорируется только при десериализации @Expose(deserialize = false) String field2; }
и при создании Gson объекта настроить правильное исключение полей с этими аннотациями:
new GsonBuilder() .addSerializationExclusionStrategy(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { Expose expose = f.getAnnotation(Expose.class); return expose != null && !expose.serialize(); }
@Override public boolean shouldSkipClass(Class c) { return false; } }) .addDeserializationExclusionStrategy(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { Expose expose = f.getAnnotation(Expose.class); return expose != null && !expose.deserialize(); }
@Override public boolean shouldSkipClass(Class c) { return false; } }) .create(); Также чтобы исключить поле можно добавить к нему модификатор transient
class Book { transient String name; }

Производительность JNI: правда или миф?

С учебы мне говорят то, что JNI это c++. И по скорости выполнения он превосходит Java. Но капаюсь я в нём и, как оказалось, вызов JNI это очень трудаемкая задача. И она требует до 12 проходов (шагов). Стоит ли вообще его использовать? И есть ли конкретные случаи когда он в Java так необходим?


Ответ

Прямо с сайта Oracle
Примеры, когда следует использовать JNI:
Стандартная библиотека JAVA не поддерживает платформенно-специфические возможности, требуемые конкретным приложением. У вас уже есть библиотека, написанная на другом языке, и вы хотите использовать ее в JAVA. Вы хотите реализовать некоторые участки кода, критичные к скорости исполнения, на языке более низкого уровня типа Ассемблера.
Пример: граф обработки аудио/видео с фильтрами. Фильтр имеет интерфейс JAVA-объекта, а алгоритм конкретного фильтра реализован на C/ASM и подключается с помощью JNI.