Многопоточность и параллельные процессы с 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 пользователей - так что это здорово! Спасибо!