Re: handling GUI resource locks between event handler and boost::thread
Lars Uffmann <aral@nurfuerspam.de> wrote in
news:63prscF28g52oU1@mid.dfncis.de:
Paavo Helde wrote:
[...]
I also note that in your example you have some evil global variables
and
I sorta must have missed the point when global variables became
"evil"... From Ansi C to C++? I have always preferred to have a couple
of global variables if that meant avoiding a lot of parameters in
function calls, because nearly every function in my application was
accessing those. Is there any big difference to capsule everything in
one big class and using class properties as "global" variables?
Nope, there should be many different classes, one big singleton class
would be the same as global variables. For example, if you create a new
thread, you almost always want to pass some data to it. This data should
be put in a struct of class which is passed directly to the thread, not
in global variables. After all, you may end up creating more thread than
one. Even if you are creating only one thread, it is good to have some
encapsulation of the data what it receives.
In case of multiple threads the global data (actually any data visible
to more than one thread) becomes especially painful because you have to
lock *each* access to *every* such variable. OK, you could argue that
different threads are accessing different data at different times by the
application logic, thus no locking needed, but this is extremely hard to
achieve in a large project and even more hard to verify that you have
done it properly. So if there is an easy way to avoid global variables
in a multithreaded application this should be done without hesitation.
you are creating boost::thread on a free function. This is not a good
idea in long term either; instead you should define a custom functor
class with operator() and needed data content and use this functor to
create a boost::thread.
erm... Now you lost me. My problem is, while I'm quite good at
programming any particular algorithm, I usually try to get some work
done with it, and so far never had the need for "functors" or even
Now that's it. Traditional threading frameworks allow to pass a void*
pointer to the started thread, where you can pass a pointer to a struct
with relevant data, which you have to cast back to the original type in
the thread functions. The boost::thread library, being a *real c++
library*, uses functors for that. So you have to learn them sooner or
later. Fortunately these are not so hard, you just define an
operator()() member function. The hardest problem technically is to
avoid the copy of the functor object (when needed), the boost::thread
library makes a copy of the thread object by default, but this can be
suppressed by a little generic wrapper I keep carrying on from one
project to another. An uncompiled example (here the objects could be
copied as well but in real life my thread objects tend to be non-
copyable):
template<typename T>
struct functor_forwarder {
T* p_;
functor_forwarder(T& p): p_(&p) {}
functor_forwarder(const functor_forwarder<T>& b): p_(b.p_) {}
void operator()() {(*p_)();}
};
class HttpServer {
unsigned short port_;
boost::thread* thread_;
public:
HttpServer(unsigned short port): port_(port) {
thread_ = new boost::thread(
functor_forwarder<HttpServer>(*this));
}
void operator()() {
// thread function
while(true) {
// accept and service connections on port_
}
}
};
int main() {
// start up some servers
HttpServer server(1234);
HttpServer another_server(4568);
// go on with other business...
}
Thank you a lot for the inputs!
You are welcome!
Paavo