Home
Ivan Sorokin's LJ

> Recent Entries
> Archive
> Friends
> User Info
> previous 20 entries

Advertisement

November 17th, 2009


02:41 am - Функциональное программирование
Кажется, я пропустил эпические дебаты (на 1632 коммента) про функциональное программирование.

Что ж, подбросим ещё аргументов на вентилятор.

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

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

Всё плохо может быть и даже имея массивы, при реализации алгоритмов на графах, изменяющих граф. Даже при работе с другими графо-подобными структурами вроде DCEL. Весь вычгеом -- это операции на DCEL'ах меняющие DCEL.

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

И не забывайте, что пока наши процессоры, остаются императивными. ;-)

В заключение хочу процитировать Александра Степанова (очень правильно пишет)

читать, это действительно, умные слова )

(39 comments | Leave a comment)

01:58 am - The thing that should be
Остались ли ещё люди, которые не убеждены в полезности ассертов и других рантайм-проверок?

Руководство, как писать unmaintainable code гласит: Avoid the assert() mechanism, because it could turn a three-day debug fest into a ten minute one. Это действительно так.

Мне пришла в голову следующая вещь. Что если сделать аналог rw-mutex'а, но который делает не защиту, а лишь проверку, что доступ не делается одновременно. Т.е. это буквально три класса (rw_mutex, read_lock, write_lock), которые работают только в дебаге.

Будь моя воля, я бы окружил все контейнеры STL и boost'а, такими штуками. Если бы shared_ptr имел такую вещь, то эту ошибку мы бы обнаружили просто как ассерт.


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

  • Их проверка очень дешевая, должна осуществляться лишь в дебаге (т.к. если он сработает в релизе, то всё равно не понятно, что с этим делать).

  • Опционально возможнен дефайн позволяющий эту проверку включать/выключать.



  • А теперь я не понимаю одну вещь. Если эта проверка такая замечательная, объясните мне, почему до меня никто не придумал её делать?

    P.S. Блин, как мне всё-таки нравиться эта идея... :-)

    (6 comments | Leave a comment)

    01:31 am - многопоточность
    Помнится как-то было много воплей на тему, того, что программы надо просто проектировать многопоточными и всё будет тип-топ.

    DC++ (и её производные клоны) является _существенно_ многопоточными программами. Потоков там... как грязи. На каждую глупость создаётся поток. Даже таймеры имеют свой поток. Причем все эти потоки вызывают разные функции в самых хитрозапутанных переплетениях. Несмотря на обилие многопоточности гуй в этой программе всё равно умудряется повисать.

    Не буду в красках расписывать блестящие технические решения, примененные при создании DC++. [info]zabivator уже много сказал.

    Но одно из них особенно дорого мне:

    static long safeInc(volatile long& v) {
       pthread_mutex_lock(&mtx);
       long ret = ++v;
       pthread_mutex_unlock(&mtx);
       return ret;
    }
    static long safeDec(volatile long& v) {
       pthread_mutex_lock(&mtx);
       long ret = --v;
       pthread_mutex_unlock(&mtx);
       return ret;
    }
    static long safeExchange(volatile long& target, long value) {
       pthread_mutex_lock(&mtx);
       long ret = target;
       target = value;
       pthread_mutex_unlock(&mtx);
       return ret;
    }


    mtx -- это глобальный mutex.

    Надо ли объяснять почему то, что здесь написано полная туфта (не из-за скорости, но из-за корректности)? Справдливости следует отметить, что этот код используется только не под винду т.е. он используется только в linuxdcpp, но тем не менее он находиться в репозитории dc++ и авторы наверняка его видели.

    Я не знаю как и почему это вообще работает (именно из-за safeExchange).

    P.S. Теперь я использую свою сборку linuxdcpp с нормальными функциями safeInc/safeDec/safeExchange, а так же с переставленными местами кнопками ok и cancel (так, чтобы ok был левее :-) ).

    P.P.S. Справедливости ради следует отметить, что у DC++ далеко не самый страшный код. И, кстати, он достаточно аккуратный. (Полагаю, по безумству с кодом ffdshow не сравнится ничто :-) )

    (17 comments | Leave a comment)

    01:02 am - многопоточность
    Не так давно поймали одну весьма редко проявляющуюся ошибку.

    В целом, программа работала хорошо. Но иногда падала. Самое удивительное, то, что программа могла работать по 11 часов (!) без каких либо проблем, а потом упасть.

    По минидампам и тем падениям которые удалось спровоцировать под отладчиков выяснилось, что падения происходят в некоторых достаточно детерминированных местах (где-то 3-5 разных мест, но места оставались одними и теми же). Все эти места так или иначе были связаны примерно с одной системой. Особенно часто падало внутри одного из map'ов и при обращении по одному из COM-овских указателей -- оказывалась не валидной таблица виртуальных функций (или может быть портился указатель на неё).

    Ясно было, что это проблема с каким-то дата рейсом.

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

    Очень забавным было, когда один раз программа упала на пробегании _пустым_ циклом for по map'у. :-)

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

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

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

    Проблема была в том, что этот shared_ptr читался из одного потока, и в это время мог одновременно меняться из другого. Ошибка достаточно банальная. Все знают, что так нельзя. У нас было аналогичное использование, и там shared_ptr защищен критической секцией.

    Посему я бы хотел подчеркнуть идею, про которую я не раз говорил (debugfest, про многопоточность): ошибка в многопоточной программе может проявлять сколь угодно редко (в данном случае программа могла работать по 11 часов в release'е, в дебаге, правда, ошибка проявлялась чаще). Причем если рейс всё-таки произойдет, совершенно не факт, что вы упадете на нём, скорее всего у программы просто испортиться состоянии и она грохнеться где-то позже. Это самые плохие ошибки, какие только бывают.

    Замечание. Это проблема не shared_ptr. Вместо него можно взять любой класс имеющий состояние. Результат бы не изменился.

    (8 comments | Leave a comment)

    November 16th, 2009


    11:45 pm - GDI+
    GDI+ библиотека микрософта для работы с векторной графикой и шрифтами. (System.Drawing является его дословной оберткой)

    В нём есть весьма забавная ошибка.

    Функции FontFamily::GenericSansSerif/GenericSerif/GenericMonospace возвращают соответствующий шрифт. Но они обращаются к системе не каждый раз когда их вызывают, а только один раз при первом вызове, и FontFamily, который им вернула система кешируют у себя.

    Но при вызове функции GdiplusShutdown шрифт в кеше протухает и GDI+ никак это не обрабатывает.

    Такая последовательность действий приводит к падению внутри GDI+:

    GdiplusStartup
    FontFamily::GenericSansSerif // GDI+ запрашивает FontFamily у системы и записывает его в кеш
    GdiplusShutdown              // шрифт в кеше стал не валидный, но GDI+ никак это не помечает
    GdiplusStartup
    FontFamily::GenericSansSerif // здесь мы получаем испорченный шрифт из кеша,
                                 // а при попытке им, что нибудь написать -- упадём


    Поэтому работая с GDI+ надо делать одно из двух:


  • Инициализировать GDI+ лишь один раз и навсегда.

  • Не пользоваться FontFamily::GenericSansSerif, а вызывать функцию получения шрифта напрямую из dll'ки: DllExports::GdipGetGenericFontFamilySansSerif. Она отрабатывает всегда хорошо.


  • (8 comments | Leave a comment)

    November 1st, 2009


    01:07 am - inotify
    Господа, скажите пожалуйста, должен ли inotify работать на /proc?

    У меня inotify корректно сообщает о создании/удалении файлов в обычных каталогах, но на /proc ничего не выдает.

    Гугл выдал inotify does not watch /proc в трекере Убунту. Значит ли это, что у меня просто неудачный дистрибутив?

    (3 comments | Leave a comment)

    12:42 am - Диграфы
    Почему этот код не скомпилируется?

    struct a {};
    
    int main()
    {
      static_cast<::a *>(0);
      return 0;
    }
    

    (7 comments | Leave a comment)

    October 24th, 2009


    11:48 pm - Линупс 2
    Сеть в Linux
    Линупс

    Сеть поборол. Почти. После отключения IPv6 "неудачные" подключения по PPPoE стали очень редки. В крайнем случае всегда можно сделать poff/pon и всё будет хорошо.

    Амарок недоигрывает последнии примерно 6 секунд (когда как) последнего трека в плейлисте.

    Календарик умер. Теперь вместо него маленькое черненькое окошечко:


    Перманентный CPU usage 10% http://rain.ifmo.ru/~sorokin/lj/sysmon.png в X-сервере. Почему он так много жрет CPU?

    Запученная система без нифига юзает 600 мб оперативной памяти. Очень много жрет Xorg. Кстати, 95 винда запускается на 4 мегах. ;-)

    Ещё много памяти жрут два питоновских скрипта. /usr/bin/update-notifier-kde -- про который было написано, что в нем лики памяти. Как они получили лики памяти на Питоне? И /usr/lib/packagekit/aptDBUSBackend.py -- не знаю, что это.

    Гуй очень тормозит. В винде Firefox просто летает по сравнению с тем, что я вижу сейчас.

    (25 comments | Leave a comment)

    October 15th, 2009


    11:08 pm
    В плюсах интегральное compile-time значение численно равное нулю может быть приведено к указателю на что-нибудь (или указателю на что-нибудь константно-волатильное).

    Поэтому работает такой код:
        int * p = 0;
        int * q = 0L;
    
    _Winnie C++ Colorizer


    Согласно разделу 4.10:
    A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type.

    Поэтому такой код тоже работает (пример из D&E):

        int * p = 2 - 2;
    
    _Winnie C++ Colorizer


    В MSVC так же работает и такой код:

        int * p = ("abc", 0);
    
    _Winnie C++ Colorizer


    В gcc нет. В компиляторах на базе EDG работает только в режиме совместимости с MSVC.

    Можно подумать, что MSVC считает результат оператора запятая compile-time константой. Это не так. Такой код он не скомпилирует:

    template <int N>
    struct T {};
    T<("abc", 3)> a;
    
    _Winnie C++ Colorizer


    Я не понимаю, как он работает.

    (1 comment | Leave a comment)

    October 5th, 2009


    12:52 am - Сеть в Linux
    Очень странная вещь происходит с pppoe. Иногда (если загрузился удачно) всё работает. А иногда (если не удачно) имена, которые должны резолвиться через dns, сообщенный через pppoe, не резолвятся. pppstats пишет, что принято 54 байта и отправлено 54 байта. Больше эти числа не меняются. Если перезагрузиться может заработать. А может и не заработать. Если загрузиться в винде pppoe работает без проблем.

    Очень странно работает пинг (даже в локальной сети). Первый ответ занимает несколько секунд, а потом всё хорошо.

    (6 comments | Leave a comment)

    October 4th, 2009


    10:20 pm - Линупс
    Я наконец-то собрался и поставил себе Линупс (kubuntu).

    Итак, обо всём по порядку.

    Вначале я просто загрузился с livecd. Первое что бросилось в глаза: в диалоге выбора стиля контролов в превью при перерисовке появляется мусор. Ну ладно это мелочь.

    После установки время перевелось на несколько часов вперёд.

    Я хотел перевести время, но тут оказалось, что если начать перетаскивать диалог с часами, то плазма падает:


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

    Кстати, по поводу календаря, угадайте, что означает число 40 в правом нижнем углу этого диалога:


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

    Затем я решил настроить локальную сеть. Я слышал про существование команды ifconfig. Чтение man'а понимания того, как оно работает не принесло. Немного потыкавшись наугад, я начал гуглить. Хочу обратить внимание, что каждая попытка гугления означала перезагрузиться в винду, погуглить, вернуться и попробовать рецепт из гугла.

    Меня спасла страничка на которой были примеры использования ifconfig'а. Вроде ifconfig eth0 192.168.3.118 -- установить ip адрес. ifconfig eth0 netmask 255.255.128.0 установить маску подсети и т.п. Почему эти примеры не написать в man? Я не понимаю. Погуглив ещё немного я прописал это всё в /etc/network/interfaces и вроде бы сеть заработала.

    Вторым делом была настройка pppoe. Здесь не помогал никакой рецепт гугла. Кто-то советовал запустить команды adsl-start/adsl-setup (но у меня нет таких команд), кто-то предлагал прописать что-то в pppoe.conf, но у меня нет такого файла. Наконец я нашел, что надо запустить pppoeconf. pppoeconf сделал мне хорошо и всё заработало. Но какие файлы он поменял я так и не понял. Вижу что он поменял /etc/network/interfaces и /etc/ppp/chap-secrets. Но может быть что-то ещё?

    Интернет у меня был. Далее я решил поставить firefox. Я прочитал, что для этого необходимо скачать его с их сайта, распаковать и всё должно работать. Однако запуская firefox я получаю следующее сообщение:
    ivan@ivan-desktop:~/programs/firefox$ ./firefox
    ./run-mozilla.sh: 399: ./firefox-bin: not found


    Самое интересное, что этот файл у меня есть. Он доступен на запуск и на чтение. Я могу сделать cat на него. Но запустить я его не могу.
    ivan@ivan-desktop:~/programs/firefox$ ls -l firefox-bin
    -rwxr-xr-x 1 ivan ivan 58228 2009-08-24 20:33 firefox-bin
    ivan@ivan-desktop:~/programs/firefox$ ./firefox-bin
    bash: ./firefox-bin: No such file or directory


    Посему у возникла пара вопросов.

    1. Правда ли что firefox-bin не запускается из-за того, что отсутствует какая-нибудь необходимая ему dll-ка(.so)?

    2. Если да, то как определить какая не разглядывая его cat в поисках строчек с именами dll-ок и проверяя все ли присутствуют в системе?

    3. Существует ли под Линупс Process Explorer, Process Monitor и vmmap аналогичные sysinternal-овским? Если нет, я считаю их просто необходимо написать. :-)


    P.S. Этот пост я написал из под Konqueror'а.
    P.P.S. Да, кстати, Линупс у меня 64-битный.

    (28 comments | Leave a comment)

    October 3rd, 2009


    01:07 am - MSVC
    Перетаскиваю одну программку с MSVC на GCC. Я и не думал, что MSVC компилирует столько всего, что не должно компилироваться.

    Например:

    typedef void (*function)(void *);
    
    void f(void *);
    
    void g(function a)
    {
        f(a);
    }
    
    _Winnie C++ Colorizer


    Указатели на функцию не должны неявно каститься к void *. MSVC не генерит ворнингов ни на каком уровне ворнингов (но правда выдаёт ошибку если отключить расширения языка /Za, но правда без этих расширений не скомпилируется ни один микросовтовский хедер).

    Или вот, например, ещё сегодня рассказал коллега:

    struct a 
    {
        template <typename T>
        void f();
    
        template <>
        void f<int>();
    };
    
    _Winnie C++ Colorizer


    Шаблонные функции члены класса нельзя специализировать. Микросовтовский компилятор разрешает это делать, но только если сам класс при этом не шаблонный.

    (7 comments | Leave a comment)

    September 28th, 2009


    12:01 am - Variadic templates
    Внезапно gcc поддерживает variadic templates.

    Ну разве это не замечательно?

    Read more... )

    Как оказалось, самое главное не забывать писать точечки ..., чтобы параметры в нужных местах экспандились. :-)

    Read more... )

    (4 comments | Leave a comment)

    September 26th, 2009


    12:25 pm
    Недавно рассказал одногруппник. Такой код не компилируется:

    template <typename T>
    struct base
    {
        typedef typename T::my1 my2;
    };
    
    struct derv : base<derv>
    {
        typedef int my1;
    };
    
    _Winnie C++ Colorizer


    с сообщением

    error C2039: 'my1' : is not a member of 'derv'

    Почему?

    (11 comments | Leave a comment)

    September 22nd, 2009


    12:07 am - Хозяйке на заметку
    Знаете ли вы, что инкрементить значения типа bool можно, а декрементить нельзя?

    void test(bool b)
    {
        ++b; // expected-warning {{incrementing expression of type bool is deprecated}}
        b++; // expected-warning {{incrementing expression of type bool is deprecated}}
        --b; // expected-error {{cannot decrement expression of type bool}}
        b--; // expected-error {{cannot decrement expression of type bool}}
    
        bool *b1 = (int *)0; // expected-error{{expected 'bool *'}}
    }
    
    _Winnie C++ Colorizer


    Взято из тестов к clang'у. Comeau честно выдаёт ворнинги. MSVC на декременты ругается, а инкременты пропускает.

    (4 comments | Leave a comment)

    September 19th, 2009


    04:27 pm - Named Lambdas
    Unified Function Syntax

    Ура, Named Lambdas!

    Они догадались, что без перегрузки лямбды нафиг никому не нужны! Только, блин, где шаблонные лямбды (аналоги функторов с шаблонным operator())?

    (Leave a comment)

    September 18th, 2009


    10:59 pm - boost::optional
    Такой код не компилируется с 1.37 бустом, если стоит опция /Zp1 (выравнивание полей структур 1 байт). Выпадает со static-assert'ом глубоко внутри буста.

    int main()
    {
        optional<int> a;
    
        return 0;
    }
    
    _Winnie C++ Colorizer


    На самом деле с /Zp2 тоже компилироваться не будет. А если под optional'ом стоит short, то только с /Zp1. Т.е. если стоит /ZpX меньше, чем выравнивание для типа переданного optional'у, то не скомпилируется.

    Кстати из-за этого же не будет работать format т.к. внутри он использует optional<locale>.

    Уже в 1.38 этот баг исправили. А у нас всё ещё используют 1.37. :-(

    (5 comments | Leave a comment)

    September 16th, 2009


    01:56 am - Про GPL и дядюшку RMS
    Меня очень удивило то, что оказалось, что лицензия CC-BY-NC-SA не является свободной т.к. запрещает коммерческое использование. Почему добрый дядюшка RMS предостерегает нас от использования лицензий запрещающих коммерческое использование?

    Оказывается, основным доходом FSF является продажа свободного программного обеспечения. Если бы все распространяли свои программы под лицензиями а-ля CC-NC, то всяких FSF никогда бы и не было.

    Нехорошесть CC-NC объясняется следующим образом: нехорошо отнимать у пользователя права, которые есть у автора. GPL предназначена для того, чтобы дать пользователю те же правда, что есть у автора.

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

    Я предлагаю другую лицензию вместо GPL. :-) Для любого некоммерческого использования она работает как GPL. Это очень хорошо иметь возможность получить исходный код, иметь возможность передать программу другу и т.п. Но для коммерческого использования автор должен получать определенную фиксированную плату от пользователя.

    Я считаю это вполне разумным. И, кстати, тогда дистрибутивы Linux'а будут стоить не $2, а как положено (думается, даже дороже Винды). И FSF не будет объяснять, что высокая цена на свободное программное обеспечение необходима, чтобы поддержать разработчиков.

    В чём я не прав?

    UPD: Кстати, на Philosophy of the GNU Project можно много всего очень странного прочитать.

    UPD2: Вот например: But I had no job, and I was looking for ways to make money from free software. So I announced that I would mail a tape to whoever wanted one, for a fee of $150. In this way, I started a free software distribution business, the precursor of the companies that today distribute entire Linux-based GNU systems. The GNU Project.

    (15 comments | Leave a comment)

    September 15th, 2009


    11:48 pm
    A Russian, a Cuban, an American and a Lawyer are in a train.

    The Russian takes a bootle of the Best Vodka out of his pack; pours some into a glass, drinks it, and says: "In USSR, we have the best vodka of the world, nowhere in the world you can find Vodka as good as the one we produce in Ukrainia. And we have so much of it, that we can just throw it away..." Saying that, he open the window and throw the rest of the bottle thru it. All the others are quite impressed.

    The Cuban takes a pack of Havanas, takes one of them, lights it and begins to smoke it saying: "In Cuba, we have the best cigars of the world: Havanas, nowhere in the world there is so many and so good cigare and we have so much of them, that we can just throw them away...". Saying that, he throws the pack of havanas thru the window. One more time, everybody is quite impressed.

    At this time, the American just stands up, opens the window, and throws the Lawyer through it...

    (2 comments | Leave a comment)

    11:17 pm - emacs man page
    NAME
    	emacs - editor macros
    SYNOPSIS
    	emacs [ options ]
    DESCRIPTION
    	This page intentionally left blank.
    SOURCE
    	MIT
    SEE ALSO
    	sam(1), vi(1)
    BUGS
    	Yes.


    http://plan9.bell-labs.com/magic/man2html/1/emacs

    (1 comment | Leave a comment)

    > previous 20 entries
    > Go to Top
    LiveJournal.com