Показаны сообщения с ярлыком boost. Показать все сообщения
Показаны сообщения с ярлыком boost. Показать все сообщения

четверг, 29 ноября 2012 г.

Boost Spirit::Qi, разбор выражений с числом элементов, большим десяти

При попытке разобрать парсером Spirit::Qi выражение, в котором более десяти элементов, компилятор сообщает об ошибках вида error: '_10' is not a member of 'qi'. Продолжительные и нерегулярные :-) раскопки исходников Qi, а так же связанных с ним Phoenix-а и fusion-а, в конце концов привели к следующим определениям, которые нужно изменить в нужную для себя сторону:
#define PHOENIX_LIMIT                   20 /* Или сколько там надо их парсить... */
#define FUSION_MAX_VECTOR_SIZE          PHOENIX_LIMIT
#define BOOST_RESULT_OF_NUM_ARGS        PHOENIX_LIMIT

После их явного задания требуемые данные успешно распарсились в вектор кортежей:
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
using boost::spirit::ascii::space_type;
//--------------------------------------------------------------------------
typedef double ValueType;
typedef ValueType First;        static const size_t FirstIndex = 0;
typedef ValueType Second;       static const size_t SecondIndex = FirstIndex + 1;
typedef ValueType Third;        static const size_t ThirdIndex = SecondIndex + 1;
typedef ValueType Fourth;       static const size_t FourthIndex = ThirdIndex + 1;
typedef ValueType Fifth;        static const size_t FifthIndex = FourthIndex + 1;
typedef ValueType Sixth;        static const size_t SixthIndex = FifthIndex + 1;
typedef ValueType Seventh;      static const size_t SeventhIndex = SixthIndex + 1;
typedef ValueType Eight;        static const size_t EightIndex = SeventhIndex + 1;
typedef ValueType Ninth;        static const size_t NinthIndex = EightIndex + 1;
typedef ValueType Tenth;        static const size_t TenthIndex = NinthIndex + 1;
typedef ValueType Eleventh;     static const size_t EleventhIndex = TenthIndex + 1;
typedef ValueType Twelfth;      static const size_t TwelfthIndex = EleventhIndex + 1;
typedef bool Locked;            static const size_t LockedIndex = TwelfthIndex + 1;
//--------------------------------------------------------------------------
typedef std::tuple<First,Second,Third,Fourth,Fifth,Sixth,       \
                   Seventh,Eight,Ninth,Tenth,Eleventh,Twelfth,  \
                   Locked> Data;
typedef std::vector<Data> DataContainer;
//--------------------------------------------------------------------------
struct phoenix_make_tuple_impl
{ /* Tuple create adapter  */
  template <typename... Args>
  struct result
  {
    typedef std::tuple<Args...> type;
  };
  template <typename... Args>
  typename result<Args...>::type operator () (Args... args) const
  {
    return std::make_tuple(args...);
  }
};
ph::function<phoenix_make_tuple_impl> const phoenix_make_tuple = phoenix_make_tuple_impl();
//--------------------------------------------------------------------------
template <typename Iterator,typename Container> \
struct ParserGrammar : qi::grammar              \
<Iterator,Container(),qi::blank_type>           \
{
  typedef typename Container::value_type Value;
  ParserGrammar(Container& container) :         \
    ParserGrammar::base_type(start)
  {
    start = qi::lit("Data") >> qi::lit("=") >>     \
      containerData                                \
      [ph::push_back(ph::ref(container),qi::_1)] % \
      qi::eol;
    containerData =                                     \
      (first >> second >> third >> fourth >>            \
       fifth >> sixth >> seventh >> eight >>            \
       ninth >> tenth >> eleventh >> twelfth >>         \
       locked)                                          \
      [qi::_val = phoenix_make_tuple                    \
       (qi::_1,qi::_2,qi::_3,qi::_4,qi::_5,qi::_6,      \
        qi::_7,qi::_8,qi::_9,qi::_10,qi::_11,qi::_12,   \
        qi::_13)];
    first = second = third = fourth = fifth =         \
      sixth = seventh = eight = ninth = tenth =       \
      eleventh = twelfth = qi::double_;
    locked = qi::bool_;
    return;
  }
  qi::rule<Iterator,Container(), qi::blank_type> start;
  qi::rule<Iterator,Value(), qi::blank_type> containerData;
  qi::rule<Iterator,double()>                   \
    first,second,third,fourth,fifth,sixth,      \
    seventh,eight,ninth,tenth,eleventh,twelfth;
  qi::rule<Iterator, bool()> locked;
};
//--------------------------------------------------------------------------
const std::string dataString = "Data = 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 10.10 11.11 12.12\n\
10.10 20.20 30.30 40.40 50.50 60.60 70.70 80.80 90.90 100.100 110.110 120.120\n";


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

Контролируемый выход из цикла в потоке

В своей деятельности я часто использую потоки. Как правило, из библиотеки boost::thread. На пару с boost::bind возможности получаются впечатляющие. Если поток однократно выполняет какое-либо действие, и сам завершается -- всё хорошо. Но зачастую требуется, чтобы поток выполнял это действие в цикле, через заданный временной интервал, и был способен получать уведомления о завершении своей работы от основного потока приложения. Для подобных целей я использую следующий механизм, основанный на совместном использовании boost::shared_mutex и boost::shared_lock:
#define BOOST_THREAD_USE_LIB
//-------------------------------------------------------------------------
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
//-------------------------------------------------------------------------
#include <string>
#include <iostream>
//-------------------------------------------------------------------------
/*
 g++ -Wall -o ./main ./main.cpp -lboost_thread
*/
//-------------------------------------------------------------------------
class Example
{
private:
 typedef boost::shared_mutex WaiterSharedMutex;
 typedef boost::shared_lock<WaiterSharedMutex> WaiterSharedLock;
 typedef boost::defer_lock_t DeferredLock;
 boost::thread workThread;
 WaiterSharedMutex waiterMutex;
 boost::posix_time::time_duration sleepTime;
 void WorkThread(void)
 {
  while(true)
  {
   WaiterSharedLock wsl(waiterMutex,DeferredLock());
   if(wsl.timed_lock(boost::get_system_time() + sleepTime))
   {
    std::cerr << "Forced exit from thread" << std::endl;
    return;
   }
   std::cerr << "Work of thread" << std::endl;
  }
  return;
 }
public:
 Example(std::size_t timeToSleep) : sleepTime(boost::posix_time::milliseconds(timeToSleep))
 {
  waiterMutex.lock();
  return;
 }
 ~Example(void)
 {
  waiterMutex.unlock();
  workThread.join();
  return;
 }
 bool Start(void)
 {
  bool result = false;
  if(workThread.joinable() == false)
  {
   waiterMutex.try_lock();
   workThread = boost::thread(boost::bind(&Example::WorkThread,this));
   result = true;
  }
  return result;
 }
 bool Stop(void)
 {
  bool result = false;
  waiterMutex.unlock();
  if(workThread.joinable() == true)
  {
   workThread.join();
  }
  return result;
 }
};
//-------------------------------------------------------------------------
int main(int argc,char** argv)
{
 std::string input;
 Example example(50000);
 while(true)
 {
  input.clear();
  std::cout << ":> ";
  std::cin >> input;
  if(!input.compare("quit"))
  {
   break;
  }
  else if(!input.compare("start"))
  {
   example.Start();
  }
  else if(!input.compare("stop"))
  {
   example.Stop();
  }
 }
 return 0;
}
Временная задержка выполнения потока обеспечивается ожиданием на mutex-е функцией timed_lock, а возможность немедленного завершения потока тем, что как сам mutex, так и его блокировка являются разделяемыми (shared_mutex и shared_lock). У разделяемого mutex-а есть две возможных блокировки: эксклюзивная, и разделяемая. Если на mutex-е эксклюзивная блокировка -- заблокировать его разделяемой будет невозможно. Обратное тоже верно. Но эксклюзивную блокировку может создавать только один поток, а разделяемую -- несколько. В представленном примере на mutex ставится эксклюзивная блокировка в конструкторе класса (строка 40), и перед попыткой пересоздать поток (строка 54). Поток (потоки), которому требуется выполнять в цикле некую функцию, пытается получить разделяемую блокировку на mutex (строка 28). Завершиться успехом это может только в случае, если основной поток отпустит эксклюзивную блокировку (строка 63, и вызов функции Stop в деструкторе класса). После чего требуется лишь дождаться завершения потока (потоков) функцией join.