На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
    > Помогите разобраться boost::asio , решил переписать сетевую часть на бусте
      К сожалению буст для меня это непонятный темный лес.
      Нужен ваш хелп.

      Сервер у меня многопоточный. Но я правильно понимаю что объект boost::asio::io_service должен быть один единственный в приложении?
      В каждом потоке достаточно вызвать io_service.run();

      правильно?

      Тут у меня возникает первая затыка. Которую я пока не знаю как решить.
      Мне необходимо в каждой асинхронной операции будь то чтение или запись знать в каком потоке она вызвалась.

      у меня имеется обертка над потоком - свой класс workerThread.
      При старте сервера я создаю ХХХ объектов workerThread и у каждого такая потоковая функция
      ExpandedWrap disabled
        void    workerThreads::workingThread( )
        {
            server s( io_service, m_serverport );
            io_service.run();
        }
      Сообщение отредактировано: progman -
        Вызывай GetCurrentThreadId(). Или тебе нужен конкретный указатель на объект workerThread? Тогда можно сделать глобальную мапу ThreadId -> workerThread
          Или так:
          ExpandedWrap disabled
            __declspec(thread) workerThreads* WorkerThread = nullptr;
            ...
            void    workerThreads::workingThread( )
            {
                WorkerThread = this;
             
                server s( io_service, m_serverport );
                io_service.run();
            }
            Цитата Pacific @
            Вызывай GetCurrentThreadId(). Или тебе нужен конкретный указатель на объект workerThread? Тогда можно сделать глобальную мапу ThreadId -> workerThread

            Я к этому "решению" и пришел.

            ExpandedWrap disabled
                  workerThread** m_threadsmap = NULL;    
                  m_threadsmap = new LPWORKERTHREADPTR[ 0x10000 ];
                  memset( m_threadsmap, 0, sizeof(LPWORKERTHREADPTR) * 0x10000 );

            и заношу в массив указатель на потоковый объект по его id перерасход памяти есть но зато мгновенный доступ в отличие от std::map
            ExpandedWrap disabled
                  for (int i = 0; i < numberOfThreads; i++)
                  {
                      workerThread* th = new workerThread( m_dbpool, io_service );        
                      int threadid = th->createThread( getServerPort());      
                      m_threadsmap[ threadid ] = th;
                  }


            Я сделал "опасное" допущение что ID потока в 32 битной windows не превысит 0хFFFF - лично я ни разу не сталкивался чтобы оно было больше 0x4000

            далее в одном и потоков куда меня коллбэк boost.asio выкинул такой вот код:
            ExpandedWrap disabled
                  int threadid        = GetCurrentThreadId();
                  workerThread* th    = m_threadsmap[ threadid ];


            вопрос в том - насколько по корану данный сабж. и не является ли мега кривыми костыялми. может быть у буста есть фича чтобы в коллбэк передать какие то данные о потоке в котором он вызвался.
            Сообщение отредактировано: progman -
              progman
              Это костыль, да. Лучше переделай на thread local глобальную переменную (пост №3) - доступ также мгновенный, только перерасхода памяти не будет, и не будет зависеть от предположений о threadid.
                Цитата Pacific @
                progman
                Это костыль, да. Лучше переделай на thread local глобальную переменную (пост №3) - доступ также мгновенный, только перерасхода памяти не будет, и не будет зависеть от предположений о threadid.

                че то я туплю - как мне оно поможет?
                ExpandedWrap disabled
                  __declspec(thread) workerThreads* WorkerThread = nullptr;
                  ...
                  void    workerThreads::workingThread( )
                  {
                      WorkerThread = this;
                   
                      server s( io_service, m_serverport );
                      io_service.run();
                  }

                ?
                  progman
                  WorkerThread будет глобальной переменной, но своей для каждого потока. Где надо - получай указатель на свой объект, локальный для текущего потока.
                    Решили соскочить с IOCP на буст? :D
                    Интересный опыт, поделитесь потом своим мнением - такое сравнение будет очень полезно для всех. :yes:
                      Цитата Oleg2004 @
                      Решили соскочить с IOCP на буст? :D
                      Интересный опыт, поделитесь потом своим мнением - такое сравнение будет очень полезно для всех. :yes:

                      под виндой boost::asio через IOCP и работает.

                      Добавлено
                      еще момент, комильфо ли отсылать данные клиенту так:
                      ExpandedWrap disabled
                        HRESULT connection::send( char* buffer, DWORD length, LPWSAOVERLAPPED lpOverlapped )
                        {
                            auto self(shared_from_this());
                            boost::asio::async_write( m_socket, boost::asio::buffer(&length, header_length), [this, self](boost::system::error_code ec, std::size_t /*length*/)
                            {
                                if (!ec)
                                {
                         
                                }
                            });
                         
                            boost::asio::async_write( m_socket, boost::asio::buffer( buffer, length), [this, self](boost::system::error_code ec, std::size_t /*length*/)
                            {
                                if (!ec)
                                {
                         
                                }
                            });
                         
                            return S_OK;
                        }

                      сначала шлю 4 байта размер а потом данные.
                      в WSASend можно было два буфера указать и отправить за один вызов. Там оно более эстетично в коде.
                      А как в бусте поэстетичнее?
                      И я надеюсь тут я асинхронную передачу данных делаю :-)
                        Цитата progman @
                        В каждом потоке достаточно вызвать io_service.run();

                        правильно?

                        Да.
                        Цитата progman @
                        Мне необходимо в каждой асинхронной операции будь то чтение или запись знать в каком потоке она вызвалась.

                        boost::this_thread::get_id()
                        ?

                        Добавлено
                        Цитата progman @
                        А как в бусте поэстетичнее?

                        Никогда так не делал. Затрудняюсь сказать, обеспечивает ли буст последовательность исполнения команд из очереди на нескольких потоках. Лучше в обработчике завершения первого write пошли второй. И, скати, почему нельзя отправить сразу 1м пакетом?
                        Сообщение отредактировано: shm -
                          Цитата shm @
                          Никогда так ты не делал. Затрудняюсь сказать, обеспечивает ли буст последовательность исполнения команд из очереди на нескольких потоках.

                          по идее оно в одном потоке вызывается.
                          сейчас запустил тест - 15 тысяч клиентов третий час нормально пашут.

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

                          Цитата shm @
                          Лучше в обработчике завершения первого write пошли второй.

                          придется выделять память и хранить передаваемый буфер.
                          Сообщение отредактировано: progman -
                            Цитата progman @
                            boost::asio через IOCP

                            Ну да:
                            ExpandedWrap disabled
                              #if defined(BOOST_ASIO_HAS_IOCP)
                              #include <boost/scoped_ptr.hpp>
                              #include <boost/asio/io_service.hpp>
                              #include <boost/asio/detail/mutex.hpp>
                              #include <boost/asio/detail/op_queue.hpp>
                              #include <boost/asio/detail/socket_types.hpp>
                              #include <boost/asio/detail/timer_op.hpp>
                              #include <boost/asio/detail/timer_queue_base.hpp>
                              #include <boost/asio/detail/timer_queue_fwd.hpp>
                              #include <boost/asio/detail/timer_queue_set.hpp>
                              #include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
                              #include <boost/asio/detail/win_iocp_operation.hpp>
                              #include <boost/asio/detail/thread.hpp>
                              #include <boost/asio/detail/push_options.hpp>

                            Такое нагромождение всего чего - не, я лично сторонник АПИ.
                            Все библиотеки подобного рода - это инструмент для RAD (rapid application development)
                            Быстро сбацать и запустить.
                            Очень даже возможно, что и будет неплохо работать - для определенных целей.
                            И, как нам всем понятно - внутри классов буста - все тот же виндовский АПИ...
                            Впрочем это все только ИМХО.
                            Вот тут интересные мысли - вроде по теме.
                            И кстати о проблеме - протокол вида "frame_size->frame_body"
                            Сообщение отредактировано: Oleg2004 -
                              Посмотрел, последовательность в твоем случае будет соблюдена. Обратил еще раз внимание на твой код, вот так:
                              Цитата progman @
                              boost::asio::buffer(&length, header_length)

                              делать нельзя. Т. к. должна обеспечиваться гарантия существования объекта до завершения операции. Другими словами, boost::asio::buffer работает по ссылке.

                              Добавлено
                              Цитата progman @
                              придется выделять память и хранить передаваемый буфер.

                              Ты так говоришь как будто это так сложно организовать.
                              Сообщение отредактировано: shm -
                                Цитата shm @
                                делать нельзя. Т. к. должна обеспечиваться гарантия существования объекта до завершения операции. Другими словами, boost::asio::buffer работает по ссылке.

                                спасибо. не учел. Думал там копирование внутри.
                                ExpandedWrap disabled
                                      HRESULT connection::send( char* buffer, DWORD length, LPWSAOVERLAPPED lpOverlapped )
                                      {
                                          char* sendbuffer = new char[length + header_length];
                                          memcpy( &sendbuffer[ 0 ], &length, header_length);
                                          memcpy( &sendbuffer[ header_length ], buffer, length );
                                   
                                          boost::asio::async_write( m_socket, boost::asio::buffer( sendbuffer, length + header_length ),
                                              std::bind( &connection::handle_write, shared_from_this(), sendbuffer, std::placeholders::_1, std::placeholders::_2 ) );
                                          
                                          return S_OK;
                                      }
                                   
                                      void connection::handle_write(char* buffer, const boost::system::error_code& a_error, std::size_t a_size)
                                      {
                                          delete[] buffer;
                                      }
                                  Я у себя привязывал буфер данных чтения и записи к объекту, связанному с сокетом. Не скажу, что это самый правильный подход, но рабочий.
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:
                                  Страницы: (3) [1] 2 3  все


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0678 ]   [ 17 queries used ]   [ Generated: 28.03.24, 08:51 GMT ]