Boost Message queue Not receiving across two processes - c++

I wrote a small test app to use the Boos Message_Queue to send data between two processes. That all worked correctly and I was able to print the data that I sent.
I moved my test code into my main project and now the main project is not waking from the Receives. The main project runs as systems so I tracked down one error and saw that the message_queue was not checking the same memory location for some reason. I defined BOOST_INTERPROCESS_SHARED_DIR_PATH and then the main project was able to open the queue created by the test app. But when the test app sends the main project never woke from its receive. The main project should be running as system and the test app as a user. But I figured since it is sharing the memory location it should work correctly?
If I open the queue in the test app again it wakes and receives all of the messages right away. Am I missing something or is this a limitation on BOOST message_queue?
The code from the test app:
MessageQueue::MessageQueue(int, boost::interprocess::permissions perm) :
mq(boost::interprocess::create_only, "TestChannel", 100, sizeof(QueueData), perm)
{
}
MessageQueue::MessageQueue(bool) :
mq(boost::interprocess::open_only, "TestChannel")
{
}
MessageQueue::~MessageQueue()
{
int num = mq.get_num_msg();
wprintf(_T("sent: %d\n"), num);
boost::interprocess::message_queue::remove("TestChannel");
}
void MessageQueue::SetCommand(int i)
{
QueueData qd;
qd.fakeInfo = i;
qd.exit = false;
CoCreateGuid(&qd.msgGuid);
mq.send(&qd, sizeof(qd), 0);
OLECHAR* uidOleStr;
if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
// Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
CString guidString(uidOleStr);
CoTaskMemFree(uidOleStr);
wprintf(_T("sent: %d, %s\n"), qd.fakeInfo, guidString);
}
void MessageQueue::WaitForCommand()
{
while(true)
{
QueueData qd;
size_t size, pri;
mq.receive(&qd, sizeof(qd), size, pri);
if (qd.fakeInfo == 2)
sendExit();
OLECHAR* uidOleStr;
if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
// Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
CString guidString(uidOleStr);
CoTaskMemFree(uidOleStr);
wprintf(_T("Recieved: %d, %s\n"), qd.fakeInfo, guidString);
if (qd.exit)
break;
}
}
void MessageQueue::sendExit()
{
QueueData qd;
qd.exit = true;
mq.send(&qd, sizeof(qd), 0);
wprintf(_T("Sent Exit"));
}
.h file:
#pragma once
#define BOOST_INTERPROCESS_SHARED_DIR_PATH "C:\\Program Files (x86)\\Users"
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/interprocess/permissions.hpp>
class QueueData
{
public:
int fakeInfo;
GUID msgGuid;
bool exit;
};
class MessageQueue
{
public:
MessageQueue(int, boost::interprocess::permissions perm);
MessageQueue(bool);
~MessageQueue();
boost::interprocess::message_queue mq;
void SetCommand(int);
void WaitForCommand();
void sendExit();
};
test app running code: (I have been using breakpoints)
void waiter()
{
MessageQueue mq(true);
mq.WaitForCommand();
}
void sender()
{
boost::interprocess::permissions perm;
perm.set_unrestricted();
try
{
boost::interprocess::message_queue::remove("TestChannel");
MessageQueue mq(2, perm);
mq.SetCommand(1);
mq.SetCommand(1);
mq.SetCommand(2);
}
catch (boost::interprocess::interprocess_exception e)
{
}
}
int main() {
waiter();
sender();
}
The code from the main project: (To test I did have it use the wait of the above code and still nothing)
void MemoryChannel::WaitForCmd( const std::function< void ( MemoryChannelCmd cmd, const char *pData, TCHAR *tempPath, GUID msgGuid ) > func )
{
QueueData mcObject;
size_t size, pri;
while (true)
{
pMCD->dataQueue.timed_receive(&mcObject, sizeof(mcObject), size, pri, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(30000));
size_t num = pMCD->dataQueue.get_num_msg();
//func(MemoryChannelCmd::MEMORY_CHANNEL_RUN_SQL_SELECT, "", _T(""), mcObject.msgGuid);
}
}
Doesn't seem to be a code issue since it works in the test app but not in the main project even sharing code.
I am at a loss.

For inter-process communication the higher privilege process must start first. Only then can lower privilege processes can connect.
In your example system process should start the queue, test app connects and then they can communicate. This is why it works when restarting the test app.
It's designed this way to prevent lower privilege users to access higher privilege user memory without permission.

Related

Sending string through queue in Freertos

I want to create a task with push button and the task sends a string to a queue and creates another task (this can also be separate task with lower priority) which reads the queue and blink led if its variable is same with the string in the queue. Otherwise system should stay in the idle mode. Im quite new with freertos and Led doesnot blink with below codes eventhough there is no compilation error. I also want to replace the datatype from char to string if it is possible. (select and zyRxBuff come from different sources, it is written as below for simplicity)
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
The handlers ;
QueueHandle_t myQueue = NULL;
TaskHandle_t QTASK1 = NULL;
TaskHandle_t QTASK2 = NULL;
Prototypes ;
void Qsender(void* p);
void Qreceiver(void* p);
Main block;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
{
xTaskCreate(Qsender, "SendingTask", 200, NULL, 1, &QTASK1);
vTaskStartScheduler();
}
while (1) {};
}
Sender Function;
void Qsender(void* p)
{
char select[10]= "BlinkLed";
myQueue = xQueueCreate(1, sizeof(select));
xQueueSend(myQueue, (void*) &select, (TickType_t)10);
if (myQueue != 0)
{
xTaskCreate(Qreceiver, "ReceivingTask", 200, NULL, 1, &QTASK2);
}
}
Receiver Function;
void Qreceiver(void* p)
{
char myRxBuff[10];
char zyRxBuff[10]="BlinkLed";
xQueueReceive(myQueue, &myRxBuff, (TickType_t)50);
if ( myRxBuff == zyRxBuff)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
}
}
Idle function;
void vApplicationIdleHook(void){__WFI();};
Nothing is happening because the program is likely executing too quickly for things to work. When your program starts it initializes everything in a fraction of a second, and if the button is not pressed then nothing happens. Then your main loop does nothing. At a minimum, you should put the button watching in a task, and that task should have a while or for loop that doesn't end.
Create a more simple system first - like, two tasks, a button-reader, and a light-emitter. The button-reader task simply checks if the button is pressed and inserts an item into the queue. The light-emitter check if there is something in the queue.
It should also be noted, that all RTOS really don't like creating and ending tasks all the time. If you're going to do so, you should read up on how tasks are created and destroyed. (https://www.freertos.org/a00125.html) Letting a task go out of context doesn't automatically clean it up, you need to use vTaskDelete - With your current functions, you'll need to clean up the QReceiver with your QSender task, which is a violation of the SOLID principals. Additionally, your QReceiver will need to send a message back that it's done. If you can get them statically working first, it will be a lot easier to get them dynamically working later.
I also noticed that you're comparing strings by address and not by content.
Qsender is sending BlinkLed
void Qsender(void* p){
char select[10]= "BlinkLed";
myQueue = xQueueCreate(1, sizeof(select));
xQueueSend(myQueue, (void*) &select, (TickType_t)10);
if (myQueue){
xTaskCreate(Qreceiver, "ReceivingTask", 200, NULL, 1, &QTASK2);
}
}
However in Qreceiver you're comparing the address of myRxBuff and zyRxBuff, when you should be doing a string-compare
void Qreceiver(void* p){
char myRxBuff[10];
char zyRxBuff[10]="BlinkLed";
xQueueReceive(myQueue, &myRxBuff, (TickType_t)50);
if ( myRxBuff == zyRxBuff){ // Offending Line
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
}
}
void Qreceiver(void* p){
char myRxBuff[10];
char zyRxBuff[10]="BlinkLed";
xQueueReceive(myQueue, &myRxBuff, (TickType_t)50);
if ( strcmp(myRxBuff, zyRxBuff) == 0){ // Should compare content now
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
}
}

Integration between Node.js and C++

I have a Node.js application that I want to be able to send a JSON-object into a C++ application.
The C++ application will use the Poco-libraries (pocoproject.org).
I want the interaction to be lighting fast, so preferably no files or network-sockets.
I have been looking into these areas:
Pipes
Shared memory
unixSockets
What should I focus on, and can someone point my direction to docs. and samples?
First of all, some more data is needed to give good advice.
In general shared memory is the fastest, since there's no transfer required, but it's also the hardest to keep fine. I'm not sure you'd be able to do that with Node though.
If this program is just running for this one task and closing it might be worth just sending your JSON to the CPP program as a startup param
myCPPProgram.exe "JsonDataHere"
The simplest thing with decent performance should be a socket connection using Unix domain sockets with some low-overhead data frame format. E.g., two-byte length followed by UTF-8 encoded JSON. On the C++ side this should be easy to implement using the Poco::Net::TCPServer framework. Depending on where your application will go in the future you may run into limits of this format, but if it's basically just streaming JSON objects it should be fine.
To make it even simpler, you can use a WebSocket, which will take care of the framing for you, at the cost of the overhead for the initial connection setup (HTTP upgrade request). May even be possible to run the WebSocket protocol over a Unix domain socket.
However, the performance difference between a (localhost only) TCP socket and a Unix domain socket may not even be significant, given all the JavaScript/node.js overhead. Also, if performance is really a concern, JSON may not even be the right serialization format to begin with.
Anyway, without more detailed information (size of JSON data, message frequency) it's hard to give a definite recommendation.
I created a TCPServer, which seems to work. However if I close the server and start it again I get this error:
Net Exception: Address already in use: /tmp/app.SocketTest
Is it not possible to re-attach to the socket if it exists?
Here is the code for the TCPServer:
#include "Poco/Util/ServerApplication.h"
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/File.h"
#include <fstream>
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServer;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::SocketAddress;
using Poco::Util::ServerApplication;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class UnixSocketServerConnection: public TCPServerConnection
/// This class handles all client connections.
{
public:
UnixSocketServerConnection(const StreamSocket& s):
TCPServerConnection(s)
{
}
void run()
{
try
{
/*char buffer[1024];
int n = 1;
while (n > 0)
{
n = socket().receiveBytes(buffer, sizeof(buffer));
EchoBack(buffer);
}*/
std::string message;
char buffer[1024];
int n = 1;
while (n > 0)
{
n = socket().receiveBytes(buffer, sizeof(buffer));
buffer[n] = '\0';
message += buffer;
if(sizeof(buffer) > n && message != "")
{
EchoBack(message);
message = "";
}
}
}
catch (Poco::Exception& exc)
{
std::cerr << "Error: " << exc.displayText() << std::endl;
}
std::cout << "Disconnected." << std::endl;
}
private:
inline void EchoBack(std::string message)
{
std::cout << "Message: " << message << std::endl;
socket().sendBytes(message.data(), message.length());
}
};
class UnixSocketServerConnectionFactory: public TCPServerConnectionFactory
/// A factory
{
public:
UnixSocketServerConnectionFactory()
{
}
TCPServerConnection* createConnection(const StreamSocket& socket)
{
std::cout << "Got new connection." << std::endl;
return new UnixSocketServerConnection(socket);
}
private:
};
class UnixSocketServer: public Poco::Util::ServerApplication
/// The main application class.
{
public:
UnixSocketServer(): _helpRequested(false)
{
}
~UnixSocketServer()
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize()
{
ServerApplication::uninitialize();
}
void defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
options.addOption(
Option("help", "h", "display help information on command line arguments")
.required(false)
.repeatable(false));
}
void handleOption(const std::string& name, const std::string& value)
{
ServerApplication::handleOption(name, value);
if (name == "help")
_helpRequested = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A server application to test unix domain sockets.");
helpFormatter.format(std::cout);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested)
{
displayHelp();
}
else
{
// set-up unix domain socket
Poco::File socketFile("/tmp/app.SocketTest");
SocketAddress unixSocket(SocketAddress::UNIX_LOCAL, socketFile.path());
// set-up a server socket
ServerSocket svs(unixSocket);
// set-up a TCPServer instance
TCPServer srv(new UnixSocketServerConnectionFactory, svs);
// start the TCPServer
srv.start();
// wait for CTRL-C or kill
waitForTerminationRequest();
// Stop the TCPServer
srv.stop();
}
return Application::EXIT_OK;
}
private:
bool _helpRequested;
};
int main(int argc, char **argv) {
UnixSocketServer app;
return app.run(argc, argv);
}
The solution I have gone for, is to use unix domain sockets. The solution will run on a Raspbian-setup and the socket-file is placed in /dev/shm, which is mounted into RAM.
On the C++ side, I use the Poco::Net::TCPServer framework as described elsewhere in this post.
On the Node.js side, I use the node-ipc module (http://riaevangelist.github.io/node-ipc/).

C++ / Qt - Passing self to pthread_create

I am working on a Qt GUI that will handle a single client. I am NOT using the Qt TCP libraries or the Qt thread library. I am creating my own Server class (more or less for the experience/learning).
I wanted to make sure what I am doing with the pthread handler isn't going to come back to haunt me in the future. My question is... Is it bad practice to pass this into the pthread_create function? Could this cause problems? It seems to work ok but I am always weary about problems lurking when working with threads.
I will be happy to share more code if it is needed. Thanks for taking a look.
Server.hpp
class Server : public Socket{
public:
....
TCPSocket *accept() throw(SocketException);
static void *listen_for_clients(void *);
void start() throw(SocketException);
void set_listen() throw(SocketException);
private:
pthread_t listen_thread;
};
Server.cpp
void HandleTCPClient(TCPSocket *sock);
TCPSocket *Server::accept() throw(SocketException)
{
int new_conn_sd;
if ( (new_conn_sd = ::accept(socket_descriptor, NULL, 0)) < 0)
{
throw SocketException("Server: accept failed", true);
}
return new TCPSocket(new_conn_sd);
}
void *Server::listen_for_clients(void *ptr)
{
Server * p = (Server *)ptr;
p->set_listen();
for (;;)
{
HandleTCPClient(p->accept());
}
return 0;
}
void Server::start() throw(SocketException)
{
if(pthread_create(&listen_thread, NULL, listen_for_clients, this)) {
throw SocketException("Server: cannot create listen thread", true);
}
}
void Server::set_listen() throw(SocketException)
{
if (listen(socket_descriptor, queue_length) < 0)
{
throw SocketException("Server: set listening socket failed", true);
}
}
void HandleTCPClient(TCPSocket *sock) {
std::cout << "Handling client ";
.....
delete sock;
}

Is there a working example of COM event handling in C++ Builder?

I am trying to connect a C++ Builder app with a .NET service app, and would like the .NET service app to be able to send events back to the C++ Builder app.
Is there a working example of a C++ Builder app which can handle COM events?
There was an error in the DocWiki regarding handling COM Events. I was able to collect some examples from various places, and put them together here for reference.
The .NET application has the following:
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace IPractLib01
{
//
// GUID's to use for the COM objects.
[Guid("ACD03FE3-E506-4D87-BF8B-CC1F52E1FF0C")]
public interface IManagedInterface
{
int SendMessage(
string message
);
}
// Source interface with "event handlers" for COM objects to implement
[Guid("1ACAB463-55A3-4B3F-BE10-6252CDD93CE8")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] // use InterfaceIsDual to get callbacks by other than InvokeEvent()
public interface IIntelliPractEvents
{
[DispId(1)] void MessageReceived();
[DispId(2)] void MessageTextReceived(string message);
}
// Delegates for the events
public delegate void MessageReceivedEventHandler();
public delegate void MessageTextReceivedEventHandler(string message);
[Guid("1F4A7EDA-EE2A-4EA3-B213-A1911C5F766E")]
[ComSourceInterfaces(typeof(IIntelliPractEvents))]
public class IPractLib01Class : IManagedInterface
{
public event MessageReceivedEventHandler MessageReceived;
public event MessageTextReceivedEventHandler MessageTextReceived;
public int SendMessage(string message)
{
if (MessageReceived != null)
{
MessageReceived();
}
if (MessageTextReceived != null)
{
int len = message.Length;
string newMessage = "The message is '" + message + "', and the length of the message is " + len;
MessageTextReceived(newMessage);
}
return 0;
}
}
}
The C++ Builder application contains:
#include "Unit1.h"
#include "IPractLib01_TLB.h" // created with Component/Import Component/Import a Type Library
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// to register the assembly dll:
// regasm IPractLib01.dll /tlb /verbose
// Need to run regasm as administrator, due to need to modify registry. If a regular user login was used to map drives, the mappings are not normally seen by the administrator login. Use "net use" in the administrator login to map them for the administrator
static TCOM_IPractLib01Class iplClass;
// The DocWiki does not take the address of the DIID_, but that does not compile
class MyEventSinkClass : public TEventDispatcher<MyEventSinkClass, &DIID_IIntelliPractEvents>
{
public:
MyEventSinkClass(IUnknown* sourceClass);
~MyEventSinkClass();
// declare the methods of DIID_IIntelliPractEvents here
void __fastcall MessageReceived();
void __fastcall MessageTextReceived(BSTR message/*[in]*/);
virtual HRESULT InvokeEvent(DISPID id, TVariant* params = 0);
IUnknown* theSource_;
};
static MyEventSinkClass* theEventSink = NULL;
static void ConnectNetHandler(void)
{
if (!iplClass)
iplClass = CoIPractLib01Class::Create();
if (!theEventSink) {
theEventSink = new MyEventSinkClass(iplClass);
}
}
// All of the events come through InvokeEvent -- change the interface to InterfaceIsDual if you want events through the other routines
HRESULT MyEventSinkClass::InvokeEvent(DISPID id, TVariant* params)
{
ShowMessage("got InvokeEvent with DISPID " + String(id));
// params would need better handling in a real app
if (params) {
String st = params->operator WideString();
ShowMessage("String is " + st);
}
return 0;
}
MyEventSinkClass::MyEventSinkClass(IUnknown* sourceClass)
{
theSource_ = sourceClass;
ConnectEvents(sourceClass);
}
MyEventSinkClass::~MyEventSinkClass()
{
DisconnectEvents(theSource_);
}
// These two routines do not get called with InterfaceIsDispatch; change that to InterfaceIsDual for these routines to be called.
void __fastcall MyEventSinkClass::MessageReceived()
{
ShowMessage("Message handler received");
}
void __fastcall MyEventSinkClass::MessageTextReceived(BSTR message/*[in]*/)
{
ShowMessage(String("Message handler received with message: ") + message);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ConnectNetHandler();
long result = -1;
TCOMIManagedInterface mif = iplClass;
if (!mif) {
ShowMessage("Unable to connect to interface");
return;
}
String theMessage = "the message";
mif->SendMessage(WideString(theMessage).c_bstr(), &result);
// check the IErrorInfo
// (Microsoft: Making a COM call that goes through a proxy-stub will clear any existing error object for the calling thread)
IErrorInfo *pperrinfo = NULL;
HRESULT hr = GetErrorInfo(0, &pperrinfo);
if (SUCCEEDED(hr) && pperrinfo) {
WideString wideStringMessage, wideStringDescription; // WideString is a wrapper for BSTR
pperrinfo->GetSource(&wideStringMessage);
pperrinfo->GetDescription(&wideStringDescription);
ShowMessage("Got error from " + String(wideStringMessage) + "; error description: " + String(wideStringDescription));
}
The DLL created by the .NET code must be registered with regasm /tlb to generate the type library, to allow C++ Builder to create the unit to implement COM. However, once the application has been created, regasm does not need to be called on the systems where this is deployed.

Multithreading and parallel processes with c++

I would like to create a c++ webserver that will perform a task for each user that lands on my website. Since the task might be computationally heavy (for now just a long sleep), I'd like to handle each user on a different thread. I'm using mongoose to set up a webserver.
The different processes (in my code below just one, aka server1) are set up correctly and seem to function correctly. However, the threads seem to be queuing one after the other so if 2 users hit the end point, the second user must wait until the first user finishes. What am I missing? Do the threads run out of scope? Is there a "thread-manager" that I should be using?
#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;
}
Long running requests should be handled like this:
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
Caveat: I'm not familiar with mongoose
My assumptions:
The serve function is polling for incoming connections
If the thread executing mg_poll_server is the same thread that triggers the call to ev_handler then your problem is the fact that ev_handler calls myEvent which starts a long running operation and blocks the thread (i.e., by calling join). In this case you're also blocking the thread which is handling the incoming connections (i.e., A subsequent client must wait for the first client to finish their work), which seems is the behavior you describe seeing.
I'm not sure what the real task is supposed to do so I can't say for sure how you should fix this. Perhaps in your use-case it may be possible to call detach otherwise you might keep track of executing threads and defer calling join on them until the server is shutdown.
James Adkison is absolutely right. So, if instead the beginning of the code looks like this:
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
//....
then the program works. Basically the difference is replacing .join() with .detach(). someFunc is running now in parallel for 2 users -- so that's great!. Thanks!