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.

Reply via email to