Многопоточность и параллельные процессы с C++

Я хотел бы создать веб-сервер C++, который будет выполнять задачу для каждого пользователя, который попадает на мой сайт. Поскольку задача может быть сложной в вычислительном отношении (пока просто долгий сон), я бы хотел обрабатывать каждого пользователя в отдельном потоке. Я использую мангуст для настройки веб-сервера.

Различные процессы (в моем коде ниже только один, он же сервер1) настроены правильно и, кажется, работают правильно. Однако потоки, похоже, стоят в очереди один за другим, поэтому, если 2 пользователя достигают конечной точки, второй пользователь должен дождаться завершения первого пользователя. Что мне не хватает? Нити выходят за рамки? Должен ли я использовать "менеджер потоков"?

#include "../../mongoose.h"
#include <unistd.h>
#include <iostream>
#include <stdlib.h>
#include <thread>


//what happens whenever someone lands on an endpoint
void myEvent(struct mg_connection *conn){
    //long delay...
    std::thread mythread(usleep, 2*5000000);
    mythread.join();
    mg_send_header(conn, "Content-Type", "text/plain");
    mg_printf_data(conn, "This is a reply from server instance # %s",
    (char *) conn->server_param);
}

static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
    if (ev == MG_REQUEST) {
        myEvent(conn);
        return MG_TRUE;
    } else if (ev == MG_AUTH) {
        return MG_TRUE;
    } else {
        return MG_FALSE; 
    }
}

static void *serve(void *server) {
    for (;;) mg_poll_server((struct mg_server *) server, 1000);
    return NULL;
}

int main(void) {
    struct mg_server *server1;
    server1 = mg_create_server((void *) "1", ev_handler);
    mg_set_option(server1, "listening_port", "8080");
    mg_start_thread(serve, server1);
    getchar();
    return 0;
}

3 ответа

Долгосрочные запросы должны обрабатываться так:

static void thread_func(struct mg_connection *conn) {
  sleep(60);  // simulate long processing
  conn->user_data = "done";  // Production code must not do that.
                             // Other thread must never access connection
                             // structure directly. This example is just
                             // for demonstration.
}

static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
  switch (ev) {
    case MG_REQUEST:
      conn->user_data = "doing...";
      spawn_thread(thread_func, conn);
      return MG_MORE;  // Important! Signal Mongoose we are not done yet
    case MG_POLL:
      if (conn->user_data != NULL && !strcmp(conn->user_data, "done")) {
        mg_printf(conn, "HTTP/1.0 200 OK\n\n  Done !");
        return MG_TRUE;  // Signal we're finished. Mongoose can close this connection
      }
      return MG_FALSE;  // Still not done

Предостережение: я не знаком с мангустом

Мои предположения:

  • serve функция опроса входящих соединений

Если поток выполняется mg_poll_server тот же поток, который запускает вызов ev_handler тогда ваша проблема в том, что ev_handler звонки myEvent которая запускает длительную операцию и блокирует поток (т. е. путем вызова join). В этом случае вы также блокируете поток, который обрабатывает входящие соединения (т. Е. Последующий клиент должен дождаться, пока первый клиент завершит свою работу), что, по-видимому, является поведением, которое вы описываете, видя.

Я не уверен, что реальная задача должна делать, поэтому я не могу точно сказать, как вы должны это исправить. Возможно, в вашем случае можно позвонить detach в противном случае вы можете отслеживать выполнение потоков и откладывать вызов join на них, пока сервер не выключен.

Джеймс Адкисон абсолютно прав. Итак, если вместо этого начало кода выглядит так:

void someFunc(struct mg_connection *conn){
    usleep(2*5000000);
    std::cout << "hello!" << std::endl;
    std::cout<< "This finished from server instance #"<<conn<<std::endl;
    mg_send_header(conn, "Content-Type", "application/json");
    mg_printf_data(conn, "{\"message\": \"This is a reply from server instance # %s\"}",
    // (char *) conn->server_param); 
}
void myEvent(struct mg_connection *conn){
    std::thread mythread(someFunc,conn);
    mythread.detach();
    std::cout<< "This is a reply from server instance #"<<(char *) conn->server_param<<std::endl;   
}

static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
    if (ev == MG_REQUEST) {
        myEvent(conn);

        return MG_TRUE;
    } else if (ev == MG_AUTH) {
    //.... exactly as before
    //....

тогда программа работает. В основном разница заключается в замене .join() с .detach(), someFunc теперь работает параллельно для 2 пользователей - так что это здорово! Спасибо!

Другие вопросы по тегам