public:
void startLogger(LogConstructorArgs args) {
loggerTid = spawn(&loggerThread, args);
}
void log(string msg, OtherOptions oo) {
loggerTid.send(LogMsg(msg, oo));
}
void stopLogger() {
loggerTid.send(QuitMsg());
}
private:
Tid loggerTid;
struct LogMsg {
string msg;
OtherOptions oo;
}
struct QuitMsg {}
void loggerThread(LogConstructorArgs args) {
Logger lg = new Logger(args);
bool cont = true;
while(cont) {
receive((LogMsg lm) { lg.log(lm.msg, lm.oo); },
(QuitMsg qm) { cont = false; });
}
}
I don't understand. In this way I should call
startLogger/stopLogger in every application thread because
loggerTid is thread related and every application thread has its
own instanse of loggerTid. Instead N+1 threads (N application and
1 logger) we will get 2*N threads (N application and N loggers).
Also we should synchronize Logger class because many instances of
them will run concurrently. This is terrible.
If you are passing objects between threads, make it shared.
This might seem annoying, but in general you should try to
shift your thinking into having thread-local objects and
communicating via structs.
But when you use global/singleton objects (any case where
there's one instance of the class), convert it into a thread,
FROM
class <name> {
this(<cons args>) {
<constructor>
}
void <method1>() {
// ...
}
int <method2>() {
int result;
// ...
return result;
}
<private fields> // you encapsulate and have no public
fields, right?
}
TO
void <name>Thread(<cons args>) {
<private fields>
<constructor>
bool cont = true;
while(cont) {
receive(
(<method1>Msg) {
// ...
},
(Tid r, <method2>Msg) {
int result;
// ...
r.send(<method2>ReturnMsg(result));
}
(QuitMsg qm) {cont = false;});
}
}
Intresting idea. I will try it. Thanks.