Страницы

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

вторник, 29 января 2019 г.

Перенос rich текста между редакторами

Подскажите, как переносится форматирование и rich текст при копировании между совершенно разными редакторами, например Google Docs в браузере и Word на ПК. Что за технология? Более конкретно: есть html в буфере обмена, надо его преобразовать так, чтобы при вставке в редактор был уже текст.


Ответ

В буфере обмена данные могут храниться в нескольких представлениях (mime-type) одновременно. Приложение-источник (copy) помещает в буфер отдельную копию данных для каждого из поддерживаемых представлений, а потребитель (paste) выбирает наиболее удобный для себя формат, из тех которые понимает. В некоторых приложениях доступен выбор представления, которое будет использовано (см. Paste Special в ворде). Пример на Qt:
QByteArray svg=BOOST_PP_STRINGIZE( Foo ); QImage image; image.loadFromData( svg );
auto*mime=new QMimeData(); mime->setText("Foo"); // Как текст (будет понимать notepad). mime->setData( "text/html" , "Foo" ); // Поймет ворд mime->setData( "image/svg+xml" ,svg ); mime->setImageData( image ); // заполняет сразу несколько графических форматов auto*clip=QApplication::clipboard(); clip->clear(); clip->setMimeData(mime);

Возможно ли комбинировать несколько способов синхронизации?

Здравствуйте. Изучаю синхронизацию потоков в Java, и, как я понял из книги, существует несколько способов синхронизации: через ключевое слово synchronized, через использование блокировок ReentrantLock и через методы wait/notify
Правильно ли я выделил эти способы? Эти способы самодостаточны? Можно ли каждый из них использовать, не прибегая к остальным? Комбинация этих способов невозможна/нежелательна/допустима/желательна?


Ответ

Давайте по пунктам:
Нет, не верно. пара методов wait()/notify() работают только в synchronized блоке. Следовательно, они не могут быть выделены в отдельную категорию. Для разграничения доступа к разделяемому ресурсу используют:
synchronized блок, или метод. некоторые абстракции, в виде реализации интерфейса java.util.concurrent.Lock, различные семафоры, барьеры и пр. Их типы с избытком представлены в пакете java.util.concurrent. Впрочем, никто не запрещает написать какую нибудь свою реализацию.
2 и 3. Способы самодостаточны и их вполне, можно использовать не смешивая. Но как правило, в многопоточных программах, могут встретиться несколько типов синхронизации. Все сильно зависит от логики и условий использования. Приведу лишь несколько примеров:
если к ресурсу обращаются не так часто и не много потоков, то производительнее будет использовать блокировку основанную на CAS'ах, т.к. это позволяет покрутившись в цикле избежав парковки треда, захватить ресурс, пускай и затратив некоторое процессорное время. если у ресурса есть два режима: чтение и запись и относительно мало потоков, которые в него пишут, то используется java.util.concurrent.ReadWriteLock. Это позволяет нескольким потокам-читателям заходить в критические области. Но если появляется писатель, то читатели ждут, когда завершится чтение.

Как работает alignas()?

int distance(void* first, void* second) { return reinterpret_cast(first) - reinterpret_cast(second); }
int main() { alignas(16) int f[4]; alignas(1024) int s[4]; std::cout << distance(f, s);
return 0; }
Никак не могу понять как работает alignas(). Почему расстояние равно 2016, а без него 24?


Ответ

alignas - это новая штука с с++11 стандарта и предназначена, чтобы устаканить то, что творится в разных компиляторах. Чтобы не говорили разработчики других языков, но иногда нужно писать немножко низкоуровневого кода, чтобы получить существенный плюс в скорости.
Как известно, процессоры лучше работают с данными в памяти, если они выровнены по границе в 4/8/16 байт. А в некоторых случаях данные обязаны быть выровнены (например, с некоторыми SSE командами и на некоторых ARM процессорах).
Что такое выравнивание по границе? Это просто адрес, который кратен заданной степени двойки. То есть, адрес 24 выровнен по границе 2, 4, 8, но не 16. Адрес 1024 выровнен по 2, 4, 8, 16, 32 и многим другим. Можно сказать и по-другому - адрес, выровненный по границе 16 в бинарном виде заканчивается на 4 нуля.
alignas как раз и заставляет компилятор сделать это выравнивание. Да, часто это идет в ущерб памяти (появляются пустоты), но в некоторых случаях (с SSE) можно получить двукратный прирост просто по той причине, что адрес выровнен по границе 16/32. Почему так происходит? Все просто - современные процессоры уже давно не загружают данные по байту из памяти - они обычно грузят как минимум по 4 байта сразу, более того, грузят по выровненным адресам по границе 4. И если нужно загрузить 4 невыровненных байта, то процессору приходится делать это в три этапа - загружаем первые байт (но при этом загружаем 4 байта), потом загружаем вторую половину, а потом складываем в памяти. А так как операция обращения к памяти - медленная - это длится достаточно долго.
Нужно ли в своем коде постоянно писать выравнивание? Нет, не нужно. Компиляторы достаточно умные и сами могут догадаться. Но есть случаи, когда это лучше сделать.
переменная используется для SSE/MMX. переменная-массив, достаточно большого размера, по которому нужно будет много итерироваться (бегать). числодробилки.
Почему расстояние равно 2016, а без него 24?
а на ideone вообще получилось -252:)
alignas говорит "выровняй", а как именно разместить в памяти - это другое дело. В Вашем случае компилятор вначале разместил первую переменную по адресу кратному 16. Вторую, нужно разместить по адресу кратному 1024. Логично, что такое может быть как сразу (потому что первая переменная занимает ровно 16 байт, так и через много-много байт (мы же не знаем адреса первой переменной).
Многие компиляторы в отладочном режиме за массивами всегда добавляют несколько байт - для того, что бы препятствовать классическому выходу за пределы массива на один элемент. Поэтому, чтобы понять, почему там именно 2016 - нужно смотреть в конкретную версию компилятора и параметры компиляции.

Как получить время простоя программы?

А именно время простоя в котором не было переключения на окно программы.
При этом может происходит работа в других программах.


Ответ

Вот вам небольшой пример на WPF:
public partial class MainWindow : Window { Stopwatch sw = new Stopwatch(); // счётчик времени
public MainWindow() { InitializeComponent(); Activated += (o, args) => sw.Start(); Deactivated += (o, args) => sw.Stop(); if (IsActive) sw.Start();
// ну и отображение StartIdleTimeUpdating(); }
async void StartIdleTimeUpdating() { while (true) { await Task.Delay(250); Target.Text = sw.Elapsed.ToString(); } } }


Результат:

Передача данных в слот не работает (через метод connect)

Есть вот такой код:
test.h
class test : public QObject{ Q_OBJECT private: ............................................... public: test(); public slots: void txt(); signals: void ok(); };
test.cpp
test::test(){ ................................................ connect(p, SIGNAL(clicked()), SIGNAL(ok())); }
void test::txt(){ l->setText("ok"); }
main.cpp
.................................................... test a, b;
QObject::connect(&a, SIGNAL(ok()), &b, SLOT(txt())); QObject::connect(&b, SIGNAL(ok()), &a, SLOT(txt())); ....................................................
Работает он замечательно. Но стоит добавить параметры передачи значений в слот как код перестает работать. Вот пример:
test.h
class test : public QObject{ Q_OBJECT private: ................................................ public: test(); public slots: void txt(QString); signals: void ok(QString); };
test.cpp
test::test(){ ...................................................... connect(p, SIGNAL(clicked()), SIGNAL(ok("word"))); }
void test::txt(QString s){ l->setText("ok"); }
main.cpp
.................................................... test a, b;
QObject::connect(&a, SIGNAL(ok()), &b, SLOT(txt())); QObject::connect(&b, SIGNAL(ok()), &a, SLOT(txt())); ....................................................
Этот код собирается но слот не отрабатывает, и почему то в редакторе строка:
connect(p, SIGNAL(clicked()), SIGNAL(ok("word")));
подчеркивается красным но в консоли ошибок нет. В чем может быть причина?


Ответ

Ответ kff из комментария:
В connect нельзя задавать параметры слота. Параметр должен приходить из сигнала
Дополню, что если сигнатура сигнала и слота не совпадает, либо необходимо выполнить дополнительные действия, то можно использовать новый синтаксис соединения сигналов и слотов, появившийся в Qt5, и lambda-выражения:
QObject::connect(p, &QPushButton::clicked, this, [this]() { Q_EMIT ok("word"); });

Как использовать в std::condition_variable функцию член класса?

В .h
class A{ std::thread thread; std::mutex mutex; std::condition_variable cv; bool run; std::queue< ResourceData > queue; public: bool resource_empty( void ){return !this->queue.empty();} ...
В реализации
while( this->run ){ std::unique_lock lk(this->mutex); cv.wait( lk, /* Сюда нужно вставить указатель на функцию */ this->resource_empty ); // просто this->queue.empty не работает // cv.wait( lk, []{ return !this->queue.empty();} ); и так }
Работает только если функция вне класса и без параметров
Хочу чтобы поток ожидал пока поступят данные в очередь. Может быть тогда есть иной способ с использованием данных класса без std::condition_variable?


Ответ

Во-первых, всегда можно использовать метод wait без второго параметра.
Во-вторых, чтобы использовать внешнюю переменную в замыкании - ее надо сначала захватить:
cv.wait( lk, [this] { return !this->queue.empty(); } );
Писать this-> необязательно - в лямбде так же, как и в любом другом месте, можно обращаться к членам this просто по имени. Но захватывать this нужно все равно:
cv.wait( lk, [this] { return !queue.empty(); } );
Также существует универсальный способ - захват всех необходимых переменных по значению:
cv.wait( lk, [=] { return !queue.empty(); } );
или по ссылке:
cv.wait( lk, [&] { return !queue.empty(); } );
Пользоваться этими способами надо с осторожностью: бесконтрольный захват переменных может привести к утечкам памяти или повреждению памяти. Но применительно к cv.wait использование [=] или [&] ничем не грозит.

понедельник, 28 января 2019 г.

Аннотация, которая не дает собрать release

Я встречал упоминание какой-то метки, возможно, аннотации, которая не дает собрать release. Используется для того, чтобы не забыть исправить нужные места в коде.
Подскажите, что это и как включить?


Ответ

Настройте Android Studio падать при сборке, если код содержит //STOPSHIP. Чтобы включить в lint проверку на //STOPSHIP, добавьте в ваш build.gradle
android { ... lintOptions { abortOnError true fatal 'StopShip' } }
Если у вас есть //STOPSHIP комментарий в коде, релизная сборка не соберётся. Кроме этого, вы также можете включить в Android Studio подсветку таких комментариев (по умолчанию выключено). Preferences → Editor → Code Style → Inspections. Ищите в поиске STOPSHIP и устанавливайте флажок для подсветки.
Источник: https://habrahabr.ru/post/319562/