Skip to content

Commit ee3593b

Browse files
committed
add multi-threaded one to many example
1 parent 9bebe7c commit ee3593b

File tree

5 files changed

+123
-0
lines changed

5 files changed

+123
-0
lines changed

examples/multi-threaded-12m/Makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
SOURCES = main.c mongoose.c # Source code files
2+
CFLAGS = -W -Wall -Wextra -g -I. # Build options
3+
4+
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
5+
CFLAGS_MONGOOSE +=
6+
7+
ifeq ($(OS),Windows_NT)
8+
# Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD
9+
PROG ?= example.exe # Use .exe suffix for the binary
10+
CC = gcc # Use MinGW gcc compiler
11+
CFLAGS += -lws2_32 # Link against Winsock library
12+
CFLAGS += -Wno-cast-function-type # Thread functions return void instead of void *
13+
DELETE = cmd /C del /f /q /s # Command prompt command to delete files
14+
else
15+
# Mac, Linux
16+
PROG ?= example
17+
CFLAGS += -lpthread # Link against POSIX threads library
18+
DELETE = rm -rf
19+
endif
20+
21+
all: $(PROG)
22+
$(RUN) ./$(PROG) $(ARGS)
23+
24+
$(PROG): $(SOURCES)
25+
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
26+
27+
clean:
28+
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM

examples/multi-threaded-12m/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See detailed tutorial at https://mongoose.ws/tutorials/multi-threaded/

examples/multi-threaded-12m/main.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright (c) 2020-2023 Cesanta Software Limited
2+
// All rights reserved
3+
//
4+
// Multithreading example.
5+
// On creation, we spawn a separate thread that sleeps for
6+
// some time to simulate some processing time, then produces an output and
7+
// sends that output to the parent connection.
8+
// That connection then broadcasts that data to all connected WebSocket
9+
// connections
10+
11+
#include "mongoose.h"
12+
13+
static void start_thread(void *(*f)(void *), void *p) {
14+
#ifdef _WIN32
15+
_beginthread((void(__cdecl *)(void *)) f, 0, p);
16+
#else
17+
#define closesocket(x) close(x)
18+
#include <pthread.h>
19+
pthread_t thread_id = (pthread_t) 0;
20+
pthread_attr_t attr;
21+
(void) pthread_attr_init(&attr);
22+
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
23+
pthread_create(&thread_id, &attr, f, p);
24+
pthread_attr_destroy(&attr);
25+
#endif
26+
}
27+
28+
struct thread_data {
29+
struct mg_mgr *mgr;
30+
unsigned long conn_id; // Parent connection ID
31+
};
32+
33+
static void *thread_function(void *param) {
34+
struct thread_data *p = (struct thread_data *) param;
35+
printf("THREAD STARTED\n");
36+
for (;;) {
37+
sleep(2);
38+
mg_wakeup(p->mgr, p->conn_id, "hi!", 3); // Send to parent
39+
}
40+
// Free all resources that were passed to us
41+
free(p);
42+
return NULL;
43+
}
44+
45+
// HTTP request callback
46+
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
47+
if (ev == MG_EV_OPEN && c->is_listening) {
48+
// Start worker thread
49+
struct thread_data *data = calloc(1, sizeof(*data)); // Worker owns it
50+
data->conn_id = c->id;
51+
data->mgr = c->mgr;
52+
start_thread(thread_function, data); // Start thread and pass data
53+
} else if (ev == MG_EV_HTTP_MSG) {
54+
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
55+
if (mg_http_match_uri(hm, "/websocket")) {
56+
mg_ws_upgrade(c, hm, NULL); // Upgrade HTTP to Websocket
57+
c->data[0] = 'W'; // Set some unique mark on a connection
58+
} else {
59+
// Serve static files
60+
// struct mg_http_serve_opts opts = {.root_dir = s_web_root};
61+
// mg_http_serve_dir(c, ev_data, &opts);
62+
}
63+
} else if (ev == MG_EV_WS_MSG) {
64+
// Got websocket frame. Received data is wm->data. Echo it back!
65+
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
66+
mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
67+
mg_iobuf_del(&c->recv, 0, c->recv.len);
68+
} else if (ev == MG_EV_WAKEUP) {
69+
struct mg_str *data = (struct mg_str *) ev_data;
70+
// Broadcast message to all connected websocket clients.
71+
// Traverse over all connections
72+
for (struct mg_connection *wc = c->mgr->conns; wc != NULL; wc = wc->next) {
73+
// Send only to marked connections
74+
if (wc->data[0] == 'W')
75+
mg_ws_send(wc, data->ptr, data->len, WEBSOCKET_OP_TEXT);
76+
}
77+
}
78+
(void) fn_data;
79+
}
80+
81+
int main(void) {
82+
struct mg_mgr mgr;
83+
mg_mgr_init(&mgr); // Initialise event manager
84+
mg_log_set(MG_LL_DEBUG); // Set debug log level
85+
mg_http_listen(&mgr, "http://localhost:8000", fn, NULL); // Create listener
86+
mg_wakeup_init(&mgr); // Initialise wakeup socket pair
87+
for (;;) { // Event loop
88+
mg_mgr_poll(&mgr, 1000);
89+
}
90+
mg_mgr_free(&mgr);
91+
return 0;
92+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../mongoose.c
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../mongoose.h

0 commit comments

Comments
 (0)