Multithreaded server - design approach - c++

I have a systemd service which acts as a server for incoming requests (API endpoint). Additionally, this service should monitor the state of the system (cpu load, ram, etc.), this is done by reading in the appropriate files in the /proc filesystem. I plan to update these values each second by spawning a dedicated thread, which will continuously read in the new values.
To my understanding a thread pool would be the wrong pattern to apply here, since these threads (probably around 4 in total) are long running (start and termination depends on the lifetime of the service). What would be a proper approach to manage these threads?
In my current implementation I have a dedicated class for each thread with some helper functions:
class Example{
public:
Example() {
t = std::thread{&Example::run, this};
}
~Example() {
t.join();
}
void read(); // read from /proc fs
void set(); // update values
void get(); // access to private data member
void run(); // thread loop, will call read and set each second
std::thread t;
private:
int data; // type int to keep it simple
}
The server then manually starts each thread on startup:
// constructor snippet
// these are member variables
t1 = Example1();
t2 = Example2();
t3 = Example3();
t4 = Example4();
I'm not sure if this is a proper approach to handle multiple, long running threads. Would it be better to create a dedicated class which handles all threads, so that the server would just have to manage this one object? Are there any other patterns for this kind of work?
Also the thread should be the only one updating the corresponding value, but there could be multiple reads happen at the same time, should a mutex be used during the update process?

Related

Using Boost::Asio for http client connection with my RestAPI server, things are good but somehow 1/20 times I hit with heap corruption

Below is code snippet from the actual code base. Please assume host, port, ioc, all are available and initialized.
// Connection establisher class
class CSSLConn: public std::enable_shared_from_this<CSSLConn>
{
:
:
};
// Class for maintaining the thread pool
class CHttpClient
{
// vector to hold connction objects
std::vector <std::shared_ptr<CSSLConn>> m_sslConnObj{};
// main method call this to create connection
void CHttpClient::Initialize(int nThreads)
{
for (int x = 0; x < nThreadCount; ++x)
{
worker_threads_.create_thread(boost::bind(&CHttpClient::WorkerThread, this));
}
// let connection get established
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
// creating threads for thread pool
void CHttpClient::WorkerThread()
{
auto client = std::make_shared<CSSLConn>(ioc, m_ctx, sHost, sPort);
client->connect(sHost.c_str(), sPort.c_str());
m_sslConnObj.push_back(client);
ioc->run();
}
};
1/20 times I hit with heap corruption while it try to create thread pool, mostly with the second thread. I am suspecting std::vector, because it allocate memory while pushing (but I am not sure is it the real culprit). I am maintaining the vector of connection to disconnect all at end.
sometimes crash happens at "boost::system::error_code background_getaddrinfo" function, but all the values looks good here.
I am not much familiar with boost, if anyone know how to debug it better, how can I see what is going inside Boost will help me a lot.
I see multiple shared objects being accessed from multiple threads
without any synchronization in place:
void WorkerThread() {
auto client = std::make_shared<CSSLConn>(ioc, m_ctx, sHost, sPort);
client->connect(sHost.c_str(), sPort.c_str());
m_sslConnObj.push_back(client);
ioc->run();
}
Here m_sslConnObj is modified without any locking. So unless
that's somehow a thread-safe container type, that's already
Undefined
Behaviour.
The same goes for other things like m_ctx.
It is also a code-smell that you are posting async work from
separate threads, as if that meant anything. io_context is
run from all the threads, so you might as well just run the threads
and create all clients from the main thread. They will still be
serviced from all the worker threads.
Just noticed, it's also weird that CSSLConn takes sHost and
sPort as constructor parameters, but then when you call
connect() on them you pass them /again/ (but differently).

Callbacks to virtual functions

I am doing some work with threading on an embedded platform. This platform provides a Thread class, and it has a start method that takes a function pointer, like this:
void do_in_parallel() {
// Some stuff to do in a new thread
}
Thread my_thread;
my_thread.start(do_in_parallel);
The problem is there is no way to pass parameters in.1 I want to solve this by creating an abstract class, call it Thread2, that extends Thread (or it could just have a Thread as instance data).
Thread2 would have a pure virtual function void run() and the goal was to pass that to Thread::start(void*()), except I soon learned that member function pointers have a different type and can't be used like this. I could make run() static, but then I still can't have more than one instance, defeating the whole purpose (not to mention you can't have a virtual static function).
Are there any workarounds that wouldn't involve changing the original Thread class (considering it's a library that I'm stuck with as-is)?
1. Global variables are a usable workaround in many cases, except when instantiating more than one thread from the same function pointer. I can't come up with a way to avoid race conditions in that case.
Write a global thread pool.
It maintains a queue of tasks. These tasks can have state.
Whe you add a task to the queue, you can choose to also request it get a thread immediately. Or you can wait for threads in the pool to be finished what they are doing.
The threads in the pool are created by the provided Thread class, and they get their marching instructions from the pool. For the most part, they should pop tasks, do them, then wait on another task being ready.
If waiting isn't permitted, you could still have some global thread manager that stores state for the threads.
The pool/manager returns the equivalent of a future<T> augmented with whatever features you want. Code that provides tasks interacts with the task through that object instead of the embedded Thread type.
A simple wrapper can be written if locking is permitted
void start(Thread& t, void (*fn)(void*), void* p)
{
static std::mutex mtx; // or any other mutex
static void* sp;
static void (*sfn)(void*);
mtx.lock();
sp = p;
sfn = fn;
t.start([]{
auto p = sp;
auto fn = sfn;
mtx.unlock();
fn(p);
});
}
This is obviously not going to scale well, all thread creations goes through the same lock, but its likely enough.
Note this is exception-unsafe, but I assume that is fine in embedded systems.
With the wrapper in place
template<typename C>
void start(Thread& t, C& c)
{
start(t, [](void* p){
(*(C*)p)();
}, &c);
}
Which allows any callable to be used. This particular implementation places the responsibility of managing the callable's lifetime on the caller.
You can create your own threaded dispatching mechanism (producer-consumer queue) built around the platform specific thread.
I assume that you have the equivalent facilities of mutex and conditional variables/signalling mechanism for the target platform.
Create a thread safe queue that can accept function objects.
The run method creates a thread and waits on the queue.
The calling thread can call post()/invoke() method that simply insert a function object to the queue.
The function object can have the necessary arguments passed to the caller thread.

Do threads share some class fields?

This is an example from C++ GUI Programming with Qt 4
I have a thread class:
class Thread : public QThread {
Q_OBJECT
public:
Thread();
void setMessage(const QString &message);
void stop();
protected:
void run();
private:
QString messageStr;
volatile bool stopped;
}
This is the relevant implementation of the the class:
Thread::Thread() {
stopped = false;
}
void Thread::run() {
while (!stopped)
std::cerr << qPrintable(messageStr);
stopped = false;
std::cerr << std::endl;
}
void Thread::stop() {
stopped = true;
}
This class is used in a ThreadDialog class which basically have two private fields Thread threadA and Thread threadB. setMessage function is called separately for them and messageStr is set to "A" and "B". Two buttons are declared inside which have clicked signals connected two to slot functions that start or stop those two threads like this:
void ThreadDialog::startOrStopThreadA() {
if (threadA.isRunning()) {
threadA.stop();
threadAButton->setText(tr("Start A"));
} else {
threadA.start();
threadAButton->setText(tr("Stop A"));
}
}
The function for threadB is the same. The problem is this, quoting directly from the book: "The stopped variable is declared volatile because it is accessed from different threads and we want to be sure that it is freshly read every time it is needed. If we omitted the volatile keyword, the compiler might optimize access to the variable, possibly leading to incorrect results."
I can't understand why these two threads would access the same field. Aren't they different instances so they have their own field stopped? Furthermore if stopped field is shared why isn't messageStr field shared too?
I can't understand why these two threads would access the same field. Aren't they different instances
so they have their own field stopped? Furthermore if stopped field is shared why isn't messageStr
field shared too?
That's not what they are saying. The field is not shared among different instances, regardless of whether there are threads involved or not. However an instance might be accessed from different threads, in that regard, the fields might be "shared" among different threads.
They are talking about the case when some other thread wishes to call threadA.stop()
If you have this code:
Thread threadA;
threadA.start();
...
threadA.stop();
There are 2 threads involved:
The thread that runs the above code
The newly created threadA that is started with the threadA.start() call
Now volatile bool stopped is accessed by thread 2 in it's run() function, and it's accessed from thread 1 when it calls threadA.stop().
This is a common confusion in multithreading. You are confusing the thread object class Thread : public QThread with the thread of execution (ie executing instructions).
There is one thread of execution which is running the code ThreadDialog::startOrStopThreadA
There is another thread of execution which is running Thread::run() and which is started by threadA.start().
Both of these threads have access to messageStr and stopped
The two instances threadA and threadB do not share stopped. They are different instances if a same class.
About this statement :
The stopped variable is declared volatile because it is accessed from
different threads and we want to be sure that it is freshly read every
time it is needed.
It means that the stopped variable is accessed from two different running threads. Here the two threads are the main application thread and the one in the run() function. It's unsafe to access the same variable from two different threads.

Multithreading and Global instances of classes?

I am using mutlithreading 'first time' for a network application, my question is two related part ,
If i represent for example bunch of messages in udp with a classes (each message a class), would it be a good practice to make instances of such classes global in order to send them at different threads, or the better approach is to use a struct having a class instance and all the socket information as a reference inside that struct (then use Pthread_create )
I reckon that in the first option , a great deal of care must be taken in order to avoid simultaneous access to data (use the pthread_mutex )
please suggest how would you approach this problem.
I really would appreciate thehelp
Thank you very much
If I understand your question correctly, you plan to have a listener thread that receveives messages and dispatches them to several threads that process these message concurently.
Here a possible approach would be to use a shared queue:
The listner push() the messages it receives on the queue :
The worker threads, if the queue is not empty(), take the next element to process (front()``andpop()`)
Of course the queue shall be locked when reading or writing elements with a mutex, unless you use a lokc-free queue implementation.
Only the queue needs to be shared. You can do this with a global definition. But on the other side, it's good practice to avoid global variables/objects whenver you can. So you'd better instantiate the queue dynamically when you create and launch your threads and pass the reference to the queueue to each of them.
With C++11 standard threads it would look somewhat like:
...
std::queue<my_message_class> work_to_do; // create queue
std::thread t1(listener, std::ref(work_to_do)); // launch listener
int n = max(2, std::thread::hardware_concurrency()-1); // maximize concurency for the hardware
std::vector<std::thread> workers;
for (int i = 0; i < n; i++) {
v.push_back(std::thread{ worker_function, std::ref(work_to_do) });
}
... // do something else and wait until it finishes
t1.join(); // wait until listner finishes
for (auto& x : workers) { // wait until all the worker threads finish.
x.join();
}
...
where void listener(std::queue<my_message_class>& q) and void worker(std::queue<my_message_class>& q) would be the functions to execute.
Of course, you could do similar things with pthreads. But the standards ones have the advantage of being platform independent.

C++ Gtk threading. Am I doing it right?

I have a gtkmm application and I'm trying to put some long running tasks into separate threads so they don't lock the GUI. Here's a tutorial I've based my design on:
http://www.velvetcache.org/2008/09/30/gtkmmglibmm-thread-example
I use Glib::Dispatcher signals to notify the GUI thread when the work is done or something needs to be updated, however I'm not sure how to pass the data between the worker thread and GUI thread. So far I've been passing a pointer to the class which creates the worker to the worker and then modifying public members of the class, but something tells me it's not the most correct to do it. Here's an example:
class Some_GUI_class
{
public:
std::string thread_message;
private:
Worker_class* worker;
void start_worker()
{
if (worker != NULL) return;
worker = new Worker_class(this);
worker->sig_message.connect(sigc::mem_fun(*this, &Some_GUI_class::display_message_from_thread);
worker.start();
}
void display_message_from_thread()
{
some_label->set_text(thread_message);
}
}
class Worker_class
{
public:
Worker_class(Some_GUI_class* gui_class) : gui_class(gui_class)
{}
void start()
{
thread = Glib::Thread::create(sigc::mem_fun(*this, &Worker_class::run), true);
}
Glib::Dispather sig_message;
protected:
Glib::Thread* thread;
Glib::Mutex mutex;
Some_GUI_class* gui_class;
void run()
{
// ...
gui_class->thread_message = "Message from a thread!";
sig_message();
}
}
This essentialy works, but I guess if the GUI thread wanted to modify thread_message at the same time there would be a problem? Is it safe to do it like this then as long as I'm sure the variables are only modified by a single thread or is there a better way?
You have a race condition. Even if your gui thread doesn't modify thread_message, allowing the GUI thread to read it while another thread is modifying it is not going to give you long term happiness. This is because std::string is not itself protected from multiple threads accessing it, and has multiple internal fields. If one thread is in the process of modifying one of its internal fields, while another is reading them, the internal state will not be consistent from the point of view of the second.
You can use a mutex in the GUI class to protect access to the variables which might be accessed by another thread. Lock and unlock the mutex in get/set routines, and use those routines for all other accesses to ensure that only one thread gets to access or modify the variables at one time.
Generally mutex usage is not enough to achieve the desired behaviour. The same worker thread (or another one if you have it) could want to send another message while first one had not been processed by the main thread yet. That is why in addition to mutex you should use message queue (e.g. object of std::deque<std::string> class) instead of just a std::string Some_GUI_class::thread_message variable to avoid this kind of message loss.