LINUX.ORG.RU

Можно ли дергать crow api из других (собственных) потоков?

 


0

1

Привет, заюзал crow для http сервера. Вопрос, который я не понял - а можно ли дергать crow апи из других (своих) потоков? Ведь он работает на базе asio, а там свой event_loop, thread_pool и всё такое, и надо помещать задание в очередь asio, которое будет выполнено его потоками. Сомнения были сразу, но после того как увидел Crow::tick(), которое даёт возможность помещать функцию в очередь на выполнение, задумался конкретно. Пример набросал, отдельный мой поток играет в пинг-понг с websocket коннектами и закрывает мертвые. Так можно?

std::mutex g_ws_mtx;
std::unordered_map<crow::websocket::connection*, steady_clock_t::time_point>
   g_ws_connections;


void ws_ping_thread_fn()
{
   while (true) {
      std::this_thread::sleep_for(...);
      if (true) {
         std::lock_guard lck(g_ws_mtx);
         for (auto i : g_ws_connections) {
            ...
            if (last time > threshold)
               // close connection
            else
               i.first->send_ping(...);
            ...
         }
      }
   }
}

int main() {
   crow::SimpleApp app;
   ...
   CROW_WEBSOCKET_ROUTE(app, "/ws")
      .onopen([&](crow::websocket::connection &conn) {
            std::lock_guard lck(g_ws_mtx);
         auto res = g_ws_connections.insert({&conn, steady_clock_t::now()});
      })
      .onclose([&](crow::websocket::connection &conn,
            const std::string& reason, uint16_t) {
         std::lock_guard lck(g_ws_mtx);
         auto res = g_ws_connections.erase(&conn);
      })
      .onmessage([&](crow::websocket::connection &conn,
            const std::string& data,
            bool is_binary) {
         std::lock_guard lck(g_ws_mtx);
         auto e = g_ws_connections.find(&conn);
         e->second = steady_clock_t::now();
      });

   std::thread ws_ping_thread(ws_ping_thread_fn);
   app.port(g_server_port).bindaddr("127.0.0.1").multithreaded().run();
   ws_ping_thread.join();
}

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



Последнее исправление: kvpfs_2 (всего исправлений: 1)

Скорее всего можно. Под капотом send_ping вызывает asio::post.

Submits a completion token or function object for execution.

От функции с таким описанием ожидаешь thread safety, потому что явно один тред постит таски, а другой тред их исполняет (и, возможно, даже не один).

Но я бы на твоём месте создал Issue в репе проекта с просьбой указать в документации thread safety статус, потому что для человека со стороны это не очевидно и от явного указания (хотя бы в списке фич «All methods are thread safe» или «All methods except initialization are thread safe» или как там оно) мир станет лучше.

https://github.com/ipkn/crow/issues/244

Вон тут пишут, что каждый сокет привязан к своему треду по round robin модели и все callback для одного подключения будут вызваны на одном и том же треде. То есть теоретически авторы могут писать код методов класса подключения не потокобезопасно.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

каждый сокет привязан к своему треду

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

конечно все зависит от реализации в crow…

сокет привязан к своему треду по round robin модели и все callback для одного подключения будут вызваны на одном и том же треде

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

anonymous2 ★★★★★
()
Последнее исправление: anonymous2 (всего исправлений: 2)