понедельник, 22 февраля 2010 г.

WPF в Visual Studio 2010: причины

Здесь рассказали о причинах, по которым в Visual Studio 2010 был использован WPF. Если опускать всю воду, то получается следующий список (в порядке описания разработчиком Visual Studio):

  1. надо было использовать WPF в каком-то известном приложении MS по маркетинговым причинам;
  2. архитектура Visual Studio, продолжашая эволюционировать с Visual C++6, начала мешать добавлению новых возможностей в студию.
Если 2-ю причину я могу принять и понять - нужно отбрасывать старое и развязывать логику и пользовательский интерфейс, чтобы удобней было жить потом. То 1-я причина (использование студии для раскрутки WPF) вызывает некоторый дискомфорт в мозгах - "Юзают мой любимый инстумент для раскрутки какой-то технологии, которую я из c++ и попробовать-то не могу!". 
А дальнейшее разъяснение, что использование WPF в студии, так и не было доведено до конца, начинает уже ставить большие знаки вопроса - зачем браться и делать на условных "62%". 

В целом странные ощущения от студии 2010 - реализация части функционала из C++0x, унифицированая система сборки проектов, и в то же время странное решение о использовании WPF для IDE.

суббота, 6 февраля 2010 г.

Статья Саттера об асинхронном API

Недавно вышла новая статья Herb Sutter'а "Prefer Futures to Baked-In "Async APIs" , в которой он анализирует различные варианты как предоставлять асинхронность операций API. В конце статьи Саттер приходит к выводу, что лучше такого не предоставлять отдельное асинхронное API, т.к. любая реализация будет мешать пользователю библиотеки, и тогда разработчик, который пользуется этой библиотекой, сможет сделать асинхронность так, как удобно именно ему, а не какому-то стороннему дяде (привет Adobe с их C++ PDF API), и только для тех функций, которые нужны ему в асинхронном виде. Как один из плюсов такого подхода, Саттер приводит остановку бессмысленного раздувания программных библиотек.

Вот интересно, а сам Саттер понимал, что его статья подтолкнёт программистов, которые используют сторонние библиотеки, к удобной им реализации асинхронности функций, даже в ущерб уже доступному асинхронному API? И зная Саттера с его стремлением к concurrent коду и эффективной реализации многопоточности, можно сказать, что он сознательно провоцирует на это.

Читайте Саттера, кто этого ещё не делает, и обдумывайте прочитанное - возможно самое вкусное вы пока не заметили.

воскресенье, 27 декабря 2009 г.

Обработка событий - что и как получать?

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

В этом же посте хочу сосредоточится на таком небольшом пункте, как аргументы в функциях-обработчиках событий. Вещь-то сейчас кажется тривиальной, но надо посмотреть на грабли, которые заложили для нас предшественники. Итак поехали:

При обработке событий можно выделить 2 аспекта: как мы получаем событие и что мы получаем с событием вместе.

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

Причины приведённые выше будут влиять на архитектурные решения, какой из вариантов выбирать: вариант с целевой подпиской выгоден в пределах одной системы и нескольких подсистем(продукты одной фирмы будут прекрасным примером реализации доставки сообщений), вариант с общей подпиской выгоден при стыковке сильно разнородных систем (практически все стандартные протоколы: MAPI, TAPI и т.п.)

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

Примером варианта с целевой подпиской может служить реализация доставки событий в COM, а примером с общей подпиской - WinAPI.

При предоставлении дополнительной информации сейчас наибольшее распространение получили два подхода:
  1. мы передаём все данные о произошедшем событии в функцию обработчик события, надеясь, что разработчику будет в дальнейшем этого достаточно.
  2. мы ничего не передаём, кроме собственно самого извещения, что событие произошло - с надеждой что разработчик получит всю нужную ему информацию сам.
А вот в этих-то зарослях и спрятаны основные грабли:

В варианте №1 ОЧЕНЬ часто забывают добавить константность для передаваемых параметров. И тогда следующий зарегистрированый обработчик может получить отнюдь не то, что ожидалось. И вообще, строить механизм вычислений с помощью обработчиков событий - не совсем хорошая идея ;)

Ещё одни тщательно разбросанные грабли (особенно их часто можно увидеть в КОМе) - это параметр, который контролирует будет ли отправлено сообщение следующему обработчику. Единственный вариант, когда это необходимо - это ситуация когда, событие в системе должно быть обработано не больше 1-го раза. В общем же случае, когда разработчик не знает кто зарегистрировался до/после него для обработки события, этот аргумент становится бесполезным или даже вредным - ибо становится возможным поломать поведение не только своей системы или системы источников событий, а и сторонних систем (на такие случаи мне везло в плагинах к Ворду :( ).

А самые заботливо укрытые грабли лежат в в варианте №2, когда общение между системой источником и системой потребителем идёт по 1-му каналу - заботливо укрывает эти грабли тот факт, что их не видно в однопоточном приложении. Но вот если в системе крутится несколько потоков, причём два и больше потоков могут отправлять события, то тут всё и начинается.
Пример:
Есть система с 2-я потоками, каждый из которых изменяет некоторую структуру данных в памяти, в целях потокобезопасности доступ к структуре закрыт критическими секциями, события отправляются после каждого изменения, но в целях быстродействия отправка событий сделана асинхронно. Потребитель событий должен забрать данные из этой же структуры данных - доступ опять же организован безопасно. На события подписан только 1 потребитель. В определённый момент времени происходит следующая ситуация: поток1 получил доступ к данным, успешно их поменял и отправил извещение, что он закончил работу; поток2 со спокойной цифровой душой получает доступ к данным, тоже их изменяет и тоже отправляет сообщение "всё ок - принимайте данные". Потребитель событий начинает забирать даныые по 1-му отправленому извещению, но то ли такт процессорный неудачно лёг, то ли sleep студент поставил, ну в общем не успел забрать данные до того как поток2 их изменил. И вот что делать в такой ситуации? - событие мы обрабатываем мы ещё 1-е, а данные уже лежат для 2-го события.
Т.е. у нас классический Data Race заботливо подготовленный системой, которая отправляет события.
Решить эту ситуацию можно сделав структуру данных, к которой имеют доступ источник событий и их потребитель, неизменной для потребителя пока он не закончит обработку события - это либо передавать в виде параметра в функцию обработчик (на что никто не пойдёт, т.к. сигнатура функций не менялась уже лет 10), либо блокировать доступ к структуре данных пока все обработчики не закончат, на что опять же никто не пойдёт - т.к. это существенно замедлит работу основной системы.

Уменьшить вероятность проблем можно запустив отдельный поток, который будет обрабатывать сообщение и копировать структуру данных как можно ближе к моменту запуска сообщения. А функции-обработчики событий будут работать как в варианте №1. Но это не решит саму проблему с подходом №2 - просто уменьшит вероятность возникновения Data Race.

Выглядит описанная ситуация довольно надуманной, но это описание работы с реализацией TAPI от Cisco. :(

Как общее итого
не лениться и гонять всю необходимую инфу через параметры события - граблей меньше и они значительно менее опасны.

пятница, 13 ноября 2009 г.

Результаты October 2009 ISO C++ Standards Meeting


Общее итого: Афигеть!

Теперь по пунктам:
1. Стандарт так и не был не утверждён, и большая часть встречи была посвящена закрытию "тёмных углов". - Это понять можно. При этом, опять же, закрыли не все проблемные места. - А вот это уже понять сложно, т.к. разработчики C++ компиляторов уже начали наступать на эти грабли (для примера можно посмотреть объяснения от MS VC++ Team - почему они в срочном порядке доделывали null_ptr в своей бете2 студии 2010).

2. Следующая встреча в марте 2010 года. Посвящена будет оставшимся проблемным местам в стандарте. Вот не понял, зачем было откладывать на полгода - что ещё осталось шлифовать? Ладно, я ещё могу понять Python с их PEP3003, ибо надо чтобы альтернативные реализации догнали основную и наиболее популярные библиотеки вышли уже с поддержкой Python3. Но что хочет дождаться комитет для C++ - просто не понимаю...

3. Они умудрились потерять главного, по их же словам, организатора и текущего председателя комитета P.J. Plauger, который к тому же был самым опытным среди них во взаимодействии с ISO. При этом он не выдержал обычного 3-хлетнего срока - вот это понять даже сложнее, чем просто уход с поста председателя из-за перевыборов. О замене даже не договорились, хотя вызывается добровольцем Саттер, как председательствовавший предыдущие 2 срока. Но это немного не тот человека из-за того, что активная фаза создания стандарта уже закончена и надо заниматься политикой, а не разработкой.

С учётом вышеизложенного, текущих темпов, того, что на мартовской встрече понадобится закрыть баги и неясности, которые остались открыты после этой встречи, и если будет предложение очередной "новой маленькой" фичи, то как бы стандарт не стал C++0xB или даже C++0xC. Хотя в последнем есть своя суровая гармония. :(

P.S.

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

среда, 21 октября 2009 г.

Блог Саттера: Опрос

Герб Саттер проводит опрос на тему: какие темы в конкурентном программировании на C++ осветить в дальнейших постах. You're welcome to participate.

В целом его блог для программистов на C++ из набора "очень желательны к ознакомлению". А цикл статей "Effective Concurrency" - это уже из набора "обязательных к прочтению", - 90% вопросов, которые возникают в процессе работы и на собеседованиях уже освещены.
Очень советую к прочтению.

P.S.

Вот и как на русский перевести правильно concurrency programming?.. Многопоточное и конкурентное программирование это всё же другие оттенки смысла.

четверг, 15 октября 2009 г.

Сортировки и сборки...

В http://www.reddit.com/r/programming/comments/9jj5z/vladimir_yaroslavskiys_dualpivot_quicksort/ прочитал об улучшении классического quicksort'а при помощи добавления второго опорного элемента. Автор показывает, что для худшего случая время работы получается на 20% лучше, чем у стандартной реализации.

Меня это заинтересовало. Да и захотелось сравнить с другими сортировками, а то использую в рабочем коде только обощённый метод из стандартной библиотеки C++, а в быстрых поделках на колене - шеловскую сортировку (настолько к этому сочетанию уже привык, что кажется - подними с кровати, напишу использование на полном автомате, не просыпаясь).

Для сравнения были выбраны следующие сортировки: реализация quicksort'а в лоб без каких-либо улучшений, реализация quicksort'а с использованием сортировки вставкой на малых массивах, dual pivot quicksort, sort из стандартной библиотеки C++ (чтобы был наглядней результат), quicksort из C runtime(насколько я понимаю, тут используется реализация из стандартной библиотеки C) и сортировка Шела с шагами 2^n -1.

Измерения проводились на векторе в 5 миллионов int'ов. Использование обощенного контейнера было основано на необходимости использовать в сравнении обобщённый sort из стандартной библиотеки C++. Среди контейнеров же был выбран вектор, т.к. хотелось посмотреть на результат qsort из C Runtime Library.

Измерения выполнялись в MS VC++2005.

Результаты получились, мягко говоря, странными.

понедельник, 28 сентября 2009 г.

Unicode - Питон, PyQt, XML

В процессе написания небольшой тулзы для себя столкнулся с граблями при чтении/записи unicode строк полученых из QT-ишного элемента управления в xml и назад. Полдня потратил на раскапывание причин и борьбу с ними.

суббота, 26 сентября 2009 г.

No Time for JAVA

Конечно, вещь известная, но не могу удержаться :)

Lyrics by Herb Sutter

I've tried Pascal, time after time
I've done my COBOL but committed no crime
C pointer mistakes, I've made a few
I've had my share of Lisp and Haskel and Scheme but I still haven't a Clu
(and on and on and on and on)

We are the champions, O Bjarne!
And we'll keep compiling till the end
You've made us champions, we are the champions
No time for Java 'cause we are the champions
Of the world!

I've taken my macros, and my function calls
I've enjoyed speed and performance and everything that goes with C, I love them all
But C's been no bed of roses, and Ada's no pleasure cruise
I want abstraction and optimization both, so I ain't gonna use...
(and on and on and on and on)


среда, 26 августа 2009 г.

Популяризатор

Оформилось при написании предыдущего поста и разрослось в отдельный пост.

В C++ есть очень много возможностей/фич, которые в связке могут давать больший выигрыш, чем  каждое по отдельности – т.е. существуют некие наборы, для которых 2+2=5. Что-то наподобие паттернов, только на языковом уровне. Мне самому это находить пока навык не позволяет, только разве что почувствовать, что оно где-то рядом. Как пример того, что может дать больший полезный выхлоп чем кажется начально: лямбды и стандартные алгоритмы, Valarray, срезы и обработка больших массивов данных…

Но Community C++ сильно нехватает Популяризатора – да, именно популяризатора с большой буквы. Причём не только русскоязычному, а и мировому.

Нет человека, который выступил бы в некотором роде “локомотивом” для C++. У Python есть Гвидо ван Россум, у C# - Microsoft целиком, даже у Java есть(был?) Sun, который раскручивал этот язык.

А у C++ никого/ничего подобного нет: Страуструп ушёл в развитие возможностей языка, Эккель сам говорит, что его больше интересует Python по различным причинам, Александреску заблудился в “лабиринтах шаблонов”, Майерс – где-то рядом с Александреску ( пока… - хотя тут возможен вариант), Степанов – ближе к научному программированию, Саттер – он подходит больше всех сейчас на роль популяризатора , но у него, уже на момент публикации “Free lunch is over” в 2003, оформилась многопоточность и всё с ней связанное, как основной приоритет. Т.е. Личности в Community C++ есть, но нет именно Популяризатора.

А ведь ситуация сейчас складывается довольно выгодная для C++: выросший рынок мульти-платформенных приложений с появлением сильного Qt может быть почти полностью привязаться к C++ на ближайшие 5-10 лет, постоянно растущий рынок embedded с его требованиями к эффективности склонен использовать C++, а не Java, C#, Python и иже с ними.

И вот хотелось бы найти Популяризатора, который смог бы раскручивать язык и использовать для этого в том числе и “языковые паттерны”.

Философия С++. Брюс Эккель.


По прочтении “Философия С++” Брюса Эккеля оформилось несколько мыслей, которые собственно и попытаюсь сформулировать.


  1. Основная мысль - Раньше её надо было прочитать, значительно раньше! Хотя бы сразу после “Паттерны проектирования” GoF. Ибо глава посвященная петтернам у Эккеля кроме собственно объяснений паттернов содержит реализацию паттернов на C++ и критику по паттернам. Т.е. позволяет паттерны хорошо утрясти в голове. При чём эккелевские примеры реализации содержат часто моменты, которые не видны при реализации “в лоб” при переносе оригинала с Java – соответственно мог переступить через несколько граблей, а не проверять их своим лбом. :(

  2. Возможности языка, которыми не владеешь хорошо, склонен рассматривать как зло предварительной оптимизации. А как только овладеваешь ими на уровне “Conscious Competence”, то уже перестаёшь понимать почему ты раньше так их боялся.

  3. В таблице моё впечатление от отдельных глав – насколько стоило их читать, т.е. что они позволяют достичь

Том/ГлаваЧто позволяет сделать

Том 1

повторить основы
Том 2
Главы 1-4повторить основы
Глава 5: Templates in DepthВдумчиво разобраться с механизмом
Глава 6-7: Generic Algorithms and ContainersОчень вдумчиво разобраться с описаными механизмами
Главы 8-9повторить основы
Глава 10: Design PatternsОчень вдумчиво разобраться
Глава 11: ConcurrencyПрочитать для интереса, за исключением Summary, которое стоит вдумчиво разобрать. Всё равно у Саттера лучше.



Да, C++Primer я читал – пока кажется “предварительной оптимизацией” ;)