mongoose/examples/multi-threaded/main.c

75 lines
2.5 KiB
C
Raw Normal View History

// Copyright (c) 2020-2023 Cesanta Software Limited
2020-12-05 19:26:32 +08:00
// All rights reserved
//
// Multithreading example.
// For each incoming request, we spawn a separate thread, that sleeps for
// some time to simulate long processing time, produces an output and
2023-12-11 01:07:54 +08:00
// sends that output to the parent connection.
2020-12-05 19:26:32 +08:00
#include "mongoose.h"
2023-02-13 04:30:18 +08:00
static void start_thread(void *(*f)(void *), void *p) {
#ifdef _WIN32
2020-12-05 19:26:32 +08:00
_beginthread((void(__cdecl *)(void *)) f, 0, p);
#else
2023-12-11 01:07:54 +08:00
#define closesocket(x) close(x)
2020-12-05 19:26:32 +08:00
#include <pthread.h>
pthread_t thread_id = (pthread_t) 0;
pthread_attr_t attr;
(void) pthread_attr_init(&attr);
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2023-02-13 04:30:18 +08:00
pthread_create(&thread_id, &attr, f, p);
2020-12-05 19:26:32 +08:00
pthread_attr_destroy(&attr);
#endif
}
2023-12-11 01:07:54 +08:00
struct thread_data {
struct mg_mgr *mgr;
unsigned long conn_id; // Parent connection ID
struct mg_str message; // Original HTTP request
};
2023-11-25 16:28:39 +08:00
2023-12-11 01:07:54 +08:00
static void *thread_function(void *param) {
struct thread_data *p = (struct thread_data *) param;
sleep(2); // Simulate long execution
mg_wakeup(p->mgr, p->conn_id, "hi!", 3); // Respond to parent
free((void *) p->message.ptr); // Free all resources that were
free(p); // passed to us
2023-02-13 04:30:18 +08:00
return NULL;
}
2020-12-05 19:26:32 +08:00
// HTTP request callback
static void fn(struct mg_connection *c, int ev, void *ev_data) {
2020-12-05 19:26:32 +08:00
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
2023-12-11 01:07:54 +08:00
if (mg_http_match_uri(hm, "/fast")) {
// Single-threaded code path, for performance comparison
// The /fast URI responds immediately
mg_http_reply(c, 200, "Host: foo.com\r\n", "hi\n");
} else {
// Multithreading code path
struct thread_data *data = calloc(1, sizeof(*data)); // Worker owns it
data->message = mg_strdup(hm->message); // Pass message
data->conn_id = c->id;
data->mgr = c->mgr;
start_thread(thread_function, data); // Start thread and pass data
2020-12-05 19:26:32 +08:00
}
2023-12-11 01:07:54 +08:00
} else if (ev == MG_EV_WAKEUP) {
struct mg_str *data = (struct mg_str *) ev_data;
mg_http_reply(c, 200, "", "Result: %.*s\n", data->len, data->ptr);
2020-12-05 19:26:32 +08:00
}
}
int main(void) {
struct mg_mgr mgr;
2023-12-11 01:07:54 +08:00
mg_mgr_init(&mgr); // Initialise event manager
2022-08-01 18:19:32 +08:00
mg_log_set(MG_LL_DEBUG); // Set debug log level
2023-12-11 01:07:54 +08:00
mg_http_listen(&mgr, "http://localhost:8000", fn, NULL); // Create listener
mg_wakeup_init(&mgr); // Initialise wakeup socket pair
for (;;) { // Event loop
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
2020-12-05 19:26:32 +08:00
return 0;
}