Инструменты пользователя

Инструменты сайта



// Source Specific Multicast и Asio

Недавно на ru.SO проскочил вопрос: как можно подключиться к SSM (Source Specific Multicast) группе?

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

2) у меня случилось однажды так подружить сетевые абстракции Asio и libev, реализовав, тем самым, реактор на Asio :-)

// C++11 regex

В синтаксисе регулярок в GCC 4.8.1/libstdc++4.8 нет поддержки квадратных скобок: []. Пришлось использовать Boost.Regex

Ах да, пруф: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631

// Build Boost on Windows with MinGW

Чисто заметка, без вдавания в детали.

Для начала нужно поставить MinGW и MSYS.

Сделать это можно двумя путями. Первый, это поставить и то и другое средствами mingw-get-inst: http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/

Но там только GCC 4.7.2, а мне нужен был GCC 4.8 (где брать свежие сборки MinGW я уже ранее писал, замечу только, что брать нужно версию с поддержкой threads-posix и dwarf, если вдруг захочется использовать бинарные сборки Qt). MSYS поставил при помощи mingw-get (http://sourceforge.net/projects/mingw/files/Installer/mingw-get/, а можно и вручную, скачивая и распаковывая файлы отсюда: http://sourceforge.net/projects/mingw/files/MSYS/). Распаковываем его, к примеру, в C:\msys, далее:

cd C:\msys\bin
mingw-get.exe update
mingw-get.exe install msys

После этого MSYS будет расположен в C:\msys\msys\1.0. Если потребуется ещё что-то от msys: mingw-get list вам в помощь.

Далее сборка Boost (у меня 1.53.0).

Распаковываем его, например в D:\boost_1_53_0

Настраиваем пути до компилятора (делаем это из запущенной копии cmd):

set PATH=c:\msys\msys\1.0\bin;c:\mingw\bin;%PATH%

Тут обращаю ваше внимание на один факт, за который разработчикам буста нужно малость по рукам настучать: буст соберётся хорошо только в случае, если MinGW поставлен в C:\MinGW и ни как иначе!

После чего собираем bjam:

cd D:\boost_1_53_0\tools\build\v2
bootstrap.bat gcc
b2 --prefix=C:\boost install
set PATH=%PATH%;C:\boost\bin

Теперь мы готовы собирать сам буст:

cd D:\boost_1_53_0\
bjam -j2 toolset=gcc --build-type=complete --prefix=C:\boost install

Вместо -j2 ставим нужное количество потоков сборки.

После продолжительной сборки буст будет расположен:

  • заголовки: C:\boost\include\boost-1_53
  • библиотеки: C:\boost\lib

И полезные параметры при сборке:

-Wno-unused-local-typedefs -DGLIBCXX_FORCE_NEW -D_WIN32_WINNT=0x0501 -DBOOST_THREAD_USE_LIB -DBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN

Для совсем ленивых, напоминаю про альтернативную сборку MinGW от Стефана, в ней он уже обновил GCC до 4.8 и Boost до 1.53. Кстати, Стефан работает в Microsoft :-D

// Boost shared_ptr, bind и thread

Правило: при использовании boost::bind будьте предельно осторожны при передаче аргументов в виде boost::shared_ptr (как и других типов умных указателей): по умолчанию используется семантика копирования, поэтому в полученном функторе будет храниться копия вашего указателя с увеличенным счётчиком ссылок. Данный факт, вкупе с использованием совместно с boost::thread, может стать иточником утечки ресурсов.

Ниже более детально.

// Охранные классы в boost::thread

Для начала, охранные классы, это не что иное как различные *_lock классы, реализующие идиому RAII, захватывающие мутекс в конструкторе (lock()) и освобождающие его в деструкторе (unlock()) - паттерн «блокировка в области видимости». Не смог придумать более корректного перевода.

Охранных классов в Boost много, легко можно в них запутаться. Но знать про них необходимо, так как почти вся библиотека boost::thread спроектирована с ориентацией на их использование.

// Удаление weak_ptr из std::list

Дано: контейнер примерно такого вида:

std::list< boost::weak_ptr<Item> > items;

Вместо boost::weak_ptr<> могу быть:

  • std::tr1::weak_ptr<>
  • std::weak_ptr<> для C++11

Задача: нужно удалить элемент по значению.

Казалось бы, просто сделай:

...
items.remove(value);
...

ан нет: для weak_ptr<> не определён оператор сравнения. Если потеоретизировать, можно предположить, почему так сделано: что бы гарантировать консистентность указателей при сравнении нужно их захватить (сделать value.lock()), т.е. создать два shared_ptr и уже их сравнивать, т.е. лишние накладные расходы.

Поэтому удаление можно делать так:

template <typename T>
bool operator == (const boost::weak_ptr<T>& a, const boost::weak_ptr<T>& b)
{
    return a.lock() == b.lock();
}

после такого std::list::remove(const T&) будет работать для всех типов. Можно и сузить до конкретного.

Либо использовать std::list::remove_if(Predicate), предикат объявить как:

struct EqPredicate
{
    const boost::weak_ptr<Item>& item;
 
    EqPredicate(const boost::weak_ptr<Item>& item)
        : item(item)
    {
    }
 
    bool operator () (const boost::weak_ptr<Item>& p) const
    {
         return p.lock() == item.lock();
    }
};

и использовать так:

std::list< boost::weak_ptr<Item> > items;
...
items.remove_if(EqPredicate(value));

Информация взята отсюда: http://stackoverflow.com/questions/1390340/how-can-i-use-stdremove-on-a-container-with-stdtr1weak-ptr

Вышесказанное верно для boost::weak_ptr, std::tr1::weak_ptr, std::weak_ptr

// Boost, CMake, кросскомпиляция

  • Q: Boost.Asio - что нужно указать в cmake среди компонентов при поиске библиотеки boost?
    A: только библиотеку system:
    find_package(Boost REQUIRED COMPONENTS system)
  • Q: Boost.Thread и кроскомпиляция - что делать, если получаем ошибку вида: undefined reference to `boost::tss_cleanup_implemented()'?
    A: для начала чуток обратно: в случае Linux, в качестве компонента при поиске библиотеки нужно указывать thread, а в случае windows (и кроскомпиляции): thread_win32, т.е. необходимо писать что-то вроде такого кода:
    set(BOOST_COMPONENTS
        program_options
        system
    )
    # Boost thread library is different on Win/Linux
    if(WIN32)
      set(BOOST_COMPONENTS ${BOOST_COMPONENTS} thread_win32)
    else()
      set(BOOST_COMPONENTS ${BOOST_COMPONENTS} thread)
    endif()
     
    ...
     
    find_package(Boost COMPONENTS ${BOOST_COMPONENTS} REQUIRED)

    Подсказку увидел тут: http://lists.gnu.org/archive/html/mingw-cross-env-list/2010-11/msg00063.html. Так же следует добавить следующее (при статической линковке):

    add_definitions(-DBOOST_THREAD_USE_LIB=1)

    . Далее, собственно, относительно самого вопроса, предлагают в случае появления такой ошибки при компиляции, поместить в любой свой исходник следующее:

    namespace boost {
     void tss_cleanup_implemented() { }
    }

    чистой воды хак :) Дополнительно написано тут: http://solarcore.blogspot.com/2010/10/boost-c-threads-mingw-mac-os-x.html

// Альтернативная сборка MinGW

Занимаясь разработкой небольшой программы, использующей сокеты, потоки и не использующей фреймворков, типа Qt, столкнулся с необходимостью собрать это дело для Windows. Подводных камней оказалось много, как результат познакомился с такими милыми сущностями, как Boost.Thread и Boost.Asio.

Но тут вспомнилось, как мне уже приходилось собирать под Windows окружение, для компиляции исходников, использующих Boost и стало грустно. Грустно настолько, что оказалось проще сделать бинарники путём кросс-компиляции. И вот, когда дело было сделано, натыкаюсь на этот ресурс:
http://nuwen.net/mingw.html

Стефан (автор этого поделия) предоставляет сборку MinGW включающую сам компилятор, набор полезных библиотек (включая Boost 1.47.0!) и некоторых полезных утилит. Пакет не требует установки, просто распаковываем в c:\mingw и пользуемся.

Так что на будущее, буду пробовать.

// Astxx: action для команды QueuePause

Парой слов, что такое Astxx небольшая библиотечка для работы с Asterisk через AMI протокол из C++. Написана с использование STL и Boost.

В одной из прошлых заметок упоминал про дружбу Qt4 и Boost.Signal - для дружбы этой библиотечки и Qt4 это и было нужно :)

Для чего нужна команда, например для организации софтовой DnD кнопки: если интерфейс будет в паузе, из очереди на него не будут переводиться звонки.

Сами классы подкатом.

UPD Переоформил в стиле Astxx

queue_pause.h
/* 
 * Additonal actions for Astxx
 * Copyright (C) 2010  Alexander Drozdov <hatred@inbox.ru>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
/** @file
 *
 * Include this file to use the QueuePause action. You should include it by hands.
 *
 */
 
#ifndef QUEUE_PAUSE_H
#define QUEUE_PAUSE_H
 
#include <astxx/manager/basic_action.h>
#include <astxx/manager/message.h>
#include <astxx/manager/error.h>
 
#include <vector>
#include <string>
 
namespace astxx
{
    namespace manager
    {                                                                                                                                                                                                                                        
        namespace action                                                                                                                                                                                                                     
        {                                                                                                                                                                                                                                    
            /** Set Queue Pause state                                                                                                                                                                                                        
            */                                                                                                                                                                                                                               
            class queue_pause : public basic_action                                                                                                                                                                                          
            {                                                                                                                                                                                                                                
            public:                                                                                                                                                                                                                          
                class error : public manager::error                                                                                                                                                                                          
                {                                                                                                                                                                                                                            
                public:                                                                                                                                                                                                                      
                    explicit error(const std::string& desc) throw() : manager::error(desc) { }                                                                                                                                               
                };                                                                                                                                                                                                                           
 
            public:                                                                                                                                                                                                                          
                /** Construct a QueuePause action.
                * @param interface      - member
                * @param is_on          - pause state
                * @param queue          - queue for process, if omited - all queues is used
                */
                queue_pause(const std::string &interface, const bool is_on = false, const std::string &queue = "") :
                    _interface(interface),
                    _queue(queue),
                    _is_on(is_on) {}
 
               /** Format this action as a message::action.
                * @return this message as a message::action
                */
                message::action action() const
                {
                    message::action action("QueuePause");
 
                    if (!_queue.empty())
                    {
                        action["Queue"] = _queue;
                    }
 
                    action["Interface"] = _interface;
 
                    std::string on_off_str = "false";
                    if (_is_on)
                    {
                        on_off_str = "true";
                    }
 
                    action["Paused"] = on_off_str;
 
                    return action;
                }
 
                message::response handle_response(message::response response)
                {
                    basic_action::handle_response(response);
                    if ("Success" != response)
                    {
                        throw queue_pause::error(response["Message"]);
                    }
 
                    return response;
                }
 
            private:
                std::string _interface;
                std::string _queue;
                bool        _is_on;
            };
 
        }
    }
}
 
#endif // QUEUE_PAUSE_H

// Boost.Signals и Qt4

Использую библиотечку astxx, которая использует Boost.Signals, использую в программе на Qt, сразу словил ошибку компиляции:

g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I../queue-test -I/usr/include/QtCore -I/usr/include -I. -I../queue-test -I. -o main.o ../queue-test/main.cpp
In file included from /usr/include/boost/signals/connection.hpp:13:0,
                 from /usr/include/boost/signals/signal_template.hpp:18,
                 from /usr/include/boost/signals/signal0.hpp:24,
                 from /usr/include/boost/signal.hpp:19,
                 from /usr/include/astxx/manager/connection.h:40,
                 from /usr/include/astxx/manager.h:32,
                 from ../queue-test/main.cpp:8:
/usr/include/boost/signals/detail/signals_common.hpp:26:13: error: expected identifier before ‘protected’
/usr/include/boost/signals/detail/signals_common.hpp:26:13: error: expected unqualified-id before ‘protected’
../queue-test/main.cpp:75:1: error: expected ‘}’ at end of input
make: *** [main.o] Error 1

Описания способов решения нашел тут:
http://www.boost.org/doc/libs/1_45_0/doc/html/signals/s04.html

Пока же, временно, определил макрос:

#define BOOST_SIGNALS_NAMESPACE boost_signals

Upd:
В .pro файле добавил:

CONFIG += no_keywords

После чего такие конструкции перестанут компилироваться:

signals:
private slots:
public slots:

Заменить на:

Q_SIGNALS:
private Q_SLOTS:
public Q_SLOTS: